#include<iostream> #define MAX 100 using namespace std; int A[MAX][MAX]; int PS[MAX][MAX]; //method1 /* 最直接的方法,当然是枚举每一个矩形区域,然后再求这个矩形区域中元素的和。时间复杂度为O(N^2 * M^2 * Sum的时间复杂度) */ int max(int x,int y) { return (x>y)?x:y; } int Sum(int i_min,int i_max,int j_min,int j_max) { int s=0; for(int i=i_min;i<=i_max;i++) for(int j=j_min;j<=j_max;j++) { s+=A[i][j]; } return s; } int MaxSum(int N,int M) { int maximum=A[1][1]; for(int i_min=1;i_min<=N;i_min++) for(int i_max=i_min;i_max<=N;i_max++) for(int j_min=1;j_min<=M;j_min++) for(int j_max=j_min;j_max<=M;j_max++) { maximum=max(maximum,Sum(i_min,i_max,j_min,j_max)); } return maximum; } //method2 /* 在二维情况下,定义“部分和”P[i][j]等于以(1,1),(i,1),(1,j),(i,j)为顶点的矩形区域的元素之和。 通过画图可以看出,以(i_min,j_min),(i_min,j_max),(i_max,j_min),(i_max,j_max)为顶点的矩形区域的元素之和 等于PS[i_max][j_max]-PS[i_min-1][j_max]-PS[i_max][j_min-1]+PS[i_min-1][j_min-1],也就是在已知“部分和”的基础 上可以用O(1)时间算出任意矩阵区域的元素之和。 不难看出,在更小的“部分和”的基础上,也能以O(1)时间得到新的“部分和”。 PS[i][j]=PS[i-1][j]+PS[i][j-1]-PS[i-1][j-1]+B[i][j] O(N*M)的时间就足够预处理并得到所有部分和。 综上所述,我们得到了一个O(N^2 * M^2)的解法。 */ void CalcPS(int N,int M) { for(int i=0;i<=N;i++)PS[i][0]=0; for(int j=0;j<=M;j++)PS[0][j]=0; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { PS[i][j]=PS[i-1][j]+PS[i][j-1]-PS[i-1][j-1]+A[i][j]; } } int MaxSum2(int N,int M) { int maximum=A[1][1]; for(int i_min=1;i_min<=N;i_min++) for(int i_max=i_min;i_max<=N;i_max++) for(int j_min=1;j_min<=M;j_min++) for(int j_max=j_min;j_max<=M;j_max++) { maximum=max(maximum,PS[i_max][j_max]-PS[i_min-1][j_max]-PS[i_max][j_min-1]+PS[i_min-1][j_min-1]); } return maximum; } //method3 /* 我们发现一维的解答可以线性完成。如果我们能将二维问题转换为一维问题,或许可以改进一下。 可以把每一列中第a行和第c行之间的元素看出一个整体。即求数组(BC(1),BC(2),...,BC(M))中的 最大的一段,其中BC[i]=B[a][i]+...+B[c][i] 我们枚举矩形上下边界,然后再用一维情况下的方法确定左右边界,就可以得到二维问题的解。 时间复杂度为O(N^2 * M) */ int MaxSum3(int N,int M) { int *a=new int[M]; int* b=new int[M]; int maximum=A[1][1]; for(int i=1;i<=N;i++) { memset(a,0,sizeof(int)*M); for(int j=i;j<=N;j++) { for(int k=1;k<=M;k++) { a[k-1]+=A[j][k]; } memset(b,0,sizeof(int)*M); b[0]=a[0]; for(int k=1;k<=M;k++) { if(b[k-1]<0)b[k]=a[k]; else b[k]=b[k-1]+a[k]; if(b[k]>maximum)maximum=b[k]; } } } return maximum; } int main() { int N,M; while(cin>>N>>M) { if(N==0 && M==0)break; memset(A,0,sizeof(int)*N*M); memset(PS,0,sizeof(int)*N*M); for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { cin>>A[i][j]; } int max=MaxSum(N,M); cout<<"子数组之和的最大值为: "<<max<<endl; CalcPS(N,M); max=MaxSum2(N,M); cout<<"子数组之和的最大值为: "<<max<<endl; max=MaxSum3(N,M); cout<<"子数组之和的最大值为: "<<max<<endl; } system("pause"); return 0; }