【编程题目】对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一

45.雅虎(运算、矩阵):
1.对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)
某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。

这道题,是我目前为止做过的最最最最最麻烦、最繁琐的题目了。

思路:

把输入的矩阵一步步还原成 0 矩阵

一个数字,只可能伴随着它上下左右四个方向的数字变化。

①如果数字比它周围四个数的和要大,那么一定不满足条件。

②如果数字小于等于四周的数字和,且其四周仅有一个数字不为0: 不为0的那个周围数字的大小 -= 当前数字大小,将当前数字置零。  因为当前数字仅可能是那个不为0的数字引起的。

③如果数字等于四周的数字和,且其四周仅有多个个数字不为0:当前与四周的数字均置0。

④如果数字小于四周的数字和,且其四周仅有多个个数字不为0:无法判断,循环继续还原。

思路不难,但是对于矩阵的四个角、四条边和中间必须分开处理,让整个代码显得又臭又长!但实际上,跟一份代码被copy了9遍差不多。我还没有什么化简的方法。如果有人知道,希望可以告诉我。

/*
45.雅虎(运算、矩阵):
1.对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)
某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
*/
#include <stdio.h>

bool canBeCreatedbyZero(int ** M, int row, int col)
{
    bool flag = false;
    do 
    {
        flag =false;
        for (int i = 0; i < row; i++) 
        {
            for (int j = 0; j < col; j++)
            {
                //打印每一次处理后的矩阵情况
                printf("
");
                for (int r = 0; r < row; r++)
                {
                    for(int c = 0; c < col; c++)
                    {
                        printf("%d", *((int *)M + r * col + c));
                    }
                    printf("
");
                }
                if ((i == 0) &&(j != 0 && j != col - 1)) //最上边
                {
                    int * r = (int *)M + i * col;
                    int * r1 = (int *)M + (i + 1) * col; 
                    if((r[j - 1] != 0 || r[j] != 0 || r[j + 1] != 0 || r1[j] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[3][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r[j - 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j - 1;
                            hasnum++;
                        }
                        if (r[j + 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j + 1;
                            hasnum++;
                        }
                        if (r1[j] != 0)
                        {
                            has[hasnum][0] = i + 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        sum = r[j - 1] + r[j + 1] + r1[j];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if((i == row - 1) &&(j != 0 && j != col - 1)) //最下边
                {
                    int * r_1 = (int *)M + (i - 1) * col;
                    int * r = (int *)M + i * col;
                    if((r_1[j] != 0 || r[j - 1] != 0 || r[j] != 0 || r[j + 1] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r_1[j] != 0)
                        {
                            has[hasnum][0] = i - 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        if (r[j - 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j - 1;
                            hasnum++;
                        }
                        if (r[j + 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j + 1;
                            hasnum++;
                        }
                        sum = r_1[j] + r[j - 1] + r[j + 1];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if ((j == 0) &&(i != 0 && i != row - 1)) //最左边
                {
                    int * r_1 = (int *)M + (i - 1) * col;
                    int * r = (int *)M + i * col;
                    int * r1 = (int *)M + (i + 1) * col; 
                    if((r_1[j] != 0 || r[j] != 0 || r[j + 1] != 0 || r1[j] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r_1[j] != 0)
                        {
                            has[hasnum][0] = i - 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        if (r[j + 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j + 1;
                            hasnum++;
                        }
                        if (r1[j] != 0)
                        {
                            has[hasnum][0] = i + 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        sum = r_1[j] + r[j + 1] + r1[j];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if ((j == col - 1) &&(i != 0 && i != row - 1))
                {
                    int * r_1 = (int *)M + (i - 1) * col;
                    int * r = (int *)M + i * col;
                    int * r1 = (int *)M + (i + 1) * col; 
                    if((r_1[j] != 0 || r[j - 1] != 0 || r[j] != 0 || r1[j] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r_1[j] != 0)
                        {
                            has[hasnum][0] = i - 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        if (r[j - 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j - 1;
                            hasnum++;
                        }
                        if (r1[j] != 0)
                        {
                            has[hasnum][0] = i + 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        sum = r_1[j] + r[j - 1] + r1[j];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if ( i == 0 && j == 0) //左上角
                {
                    int * r = (int *)M + i * col;
                    int * r1 = (int *)M + (i + 1) * col; 
                    if(( r[j] != 0 || r[j + 1] != 0 || r1[j] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                    
                        if (r[j + 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j + 1;
                            hasnum++;
                        }
                        if (r1[j] != 0)
                        {
                            has[hasnum][0] = i + 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        sum = r[j + 1] + r1[j];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if (i == row - 1 && j == 0) //左下角
                {
                    int * r_1 = (int *)M + (i - 1) * col;
                    int * r = (int *)M + i * col;
                    if((r_1[j] != 0|| r[j] != 0 || r[j + 1] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r_1[j] != 0)
                        {
                            has[hasnum][0] = i - 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        if (r[j + 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j + 1;
                            hasnum++;
                        }
                        sum = r_1[j] + r[j + 1];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if (i == 0 && j == col - 1) //右上角
                {
                    int * r = (int *)M + i * col;
                    int * r1 = (int *)M + (i + 1) * col; 
                    if((r[j - 1] != 0 || r[j] != 0 || r1[j] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r[j - 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j - 1;
                            hasnum++;
                        }
                        if (r1[j] != 0)
                        {
                            has[hasnum][0] = i + 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        sum = r[j - 1] + r1[j];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if (i == row - 1 && j == col - 1) //右下角
                {
                    int * r_1 = (int *)M + (i - 1) * col;
                    int * r = (int *)M + i * col;
                    if(r_1[j] != 0 || r[j - 1] != 0 || r[j] != 0) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r_1[j] != 0)
                        {
                            has[hasnum][0] = i - 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        if (r[j - 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j - 1;
                            hasnum++;
                        }
                        
                        sum = r_1[j] + r[j - 1];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
                else if(i != 0 && i != row - 1 && j != 0 && j != col - 1) //非边界情况
                {
                    int * r_1 = (int *)M + (i - 1) * col;
                    int * r = (int *)M + i * col;
                    int * r1 = (int *)M + (i + 1) * col; 
                    if((r_1[j] != 0 || r[j - 1] != 0 || r[j] != 0 || r[j + 1] != 0 || r1[j] != 0)) //只在有非零元素的时候才做下面处理
                    {    
                        flag = true;
                        int has[4][2];
                        int hasnum = 0; //该中心点上下左右有几个不为0的数字
                        int sum = 0; //该中心点四周的数字相加的值
                        if (r_1[j] != 0)
                        {
                            has[hasnum][0] = i - 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        if (r[j - 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j - 1;
                            hasnum++;
                        }
                        if (r[j + 1] != 0)
                        {
                            has[hasnum][0] = i;
                            has[hasnum][1] = j + 1;
                            hasnum++;
                        }
                        if (r1[j] != 0)
                        {
                            has[hasnum][0] = i + 1;
                            has[hasnum][1] = j;
                            hasnum++;
                        }
                        sum = r_1[j] + r[j - 1] + r[j + 1] + r1[j];

                        if (r[j] > sum) //数字大于周围的和 返回false
                        {
                            return false;
                        }
                        else if(hasnum == 1) //旁边只有一个不为0的 中心数字与旁边数字同步减少
                        {
                            int t = r[j];
                            r[j] = 0;
                            *((int *)M + has[0][0] * col + has[0][1]) -= t;
                        }
                        else if(r[j] == sum) //中心数字与旁边不为0的数字和相等
                        {
                            for(int ii = 0; ii < hasnum; ii++)
                            {
                                *((int *)M + has[ii][0] * col + has[ii][1]) = 0;
                            }
                            r[j] = 0;
                        }
                    }
                }
            }

        }

        
    }while(flag == true);
    return true;
}

int main()
{
    int a[4][4] = {{0,1,0,0},
                   {1,2,2,1},
                   {0,1,3,0},
                   {0,0,1,0}};
     bool f = canBeCreatedbyZero((int **)a, 4, 4);

     getchar();
     return 0;

}

网上找答案:居然没有找到别人写好的代码。都是说个思路就完了!!

有说用最大流可以搞定 http://blog.csdn.net/lihappy999/article/details/7395934

有说匈牙利算法的

http://www.cnblogs.com/GoAhead/archive/2012/06/01/2531144.html 给了个方法 但我没看懂

最让我无语的是翻答案就得到这样一段话:

A assignment problem. Two ways to solve. 1: duplicate each cell to as many as its value,
do Hungarian algorithm. Denote the sum of the matrix as M, the edge number is 2M, so
the complexity is 2*M*M; 2: standard maximum flow. If the size of matrix is NxN, then the
algorithm using Ford Fulkerson algorithm is M*N*N.
too complex... I will do this when I have time...

原文地址:https://www.cnblogs.com/dplearning/p/3905518.html