#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;
}

  

posted on 2012-11-07 09:04  吉大依恋  阅读(402)  评论(0编辑  收藏  举报