编程之美——子数组之和的最大值(二维)

编程之美——子数组之和的最大值(二维)


问题:给一个大的矩阵,在其中间找一个小矩阵,使得这个小矩阵所有元素的和最大。

方法一:

   1,首先将mem二维数组做成一个保存部分和的矩阵。即mem[i][j]保存的是(1,1)~(i,j)的矩阵和。O(N*M)

   2,从部分和矩阵mem可以推得任意(x1,y1)~(x2,y2)的子矩阵和。推导公式:=mem[x2][y2]-mem[x1-1][y2]-mem[x2][y1-1]+mem[x1-1][y1-1];   O(1)

   3,遍历所有可能的情况(x1,y1)~(x2,y2),找最大值。其中x1变化范围1~N,y1变化范围1~M, x2变化范围x1~N,y2变化范围y1~M,    O(N^2*M^2).

   4,最终时间:O(N*M)+O(N^2*M^2)=O(N^2*M^2).

代码为:
#include<iostream>
using namespace std;
#define MAX 100
int N,M;
int array[MAX][MAX];
int mem[MAX][MAX];
int subMatrix(int x1,int y1,int x2,int y2)
{
  return mem[x2][y2]-mem[x1-1][y2]-mem[x2][y1-1]-mem[x1-1][y1-1];
}

int main()
{
  while(cin>>N>>M)
  {
    for(int i=1;i<=N;i++)
{
 for(int j=1;j<=M;j++)
 {
   cin>>array[i][j];
 }
}
memset(mem,0,MAX*MAX);
for(int k=1;k<=N;k++)
{
 for(int q=1;q<=M;q++)
 {
   mem[k][q]=mem[k-1][q]+mem[k][q-1]-mem[k-1][q-1]+array[k][q];
 }
}
int max=INT_MIN;
int posx1,posx2,posy1,posy2;
for(int x1=1;x1<=N;x1++)
{
 for(int y1=1;y1<=M;y1++)
 {
   for(int x2=x1;x2<=N;x2++)
{
 for(int y2=y1;y2<=M;y2++)
 {
   int d=subMatrix(x1,y1,x2,y2);
if(d>max)
{
 max=d;
 posx1=x1;
 posx2=x2;
 posy1=y1;
 posy2=y2;
}
 }
}
 }
}
cout<<max<<endl;
cout<<“(“<<posx1<<“,”<<posy1<<“)”<<endl;
cout<<“(“<<posx2<<“,”<<posy2<<“)”<<endl;
  }
}



方法二:(将二维数组转换为一维数组)

      注意之前的效率分析,其实现在调用计算任意矩形的开销都在O(1),因为函数subMatrix是O(1)的。所以关键是我在找最大子矩阵和是不得不得遍历所有的可能性造成了O(N^2*M^2)的开销。

      现在改进如下,首先遍历所有的行,即,用两平行条线划分X方向。这是O(N^2)的,然后将夹在中间的找可能的列看做一维上找最大的子序列和,只需O(M)时间。所以最终为O(N^2*M)效率。

代码为:
//二维数组中子数组之和的最大值
#include<iostream>
#include<climits>
using namespace std;
#define MAX 100
int N,M;
int array[MAX][MAX];
int mem[MAX][MAX];
int memy[MAX];
int posybegin[MAX];
int subMatrix(int x1,int y1,int x2,int y2)
{
  return mem[x2][y2]-mem[x1-1][y2]-mem[x2][y1-1]-mem[x1-1][y1-1];
}

int main()
{
  while(cin>>N>>M)
  {
    for(int a=1;a<=N;a++)
{
 for(int j=1;j<=M;j++)
 {
   cin>>array[a][j];
 }
}
    memset(mem,0,MAX*MAX);
for(int i=1;i<=N;i++)
{
 for(int j=1;j<=M;j++)
 {
   mem[i][j]=mem[i-1][j]+mem[i][j-1]-mem[i-1][j-1]+array[i][j];
 }
}
int Max=INT_MIN;
int posx1,posx2,posy1,posy2;
for(int x1=1;x1<=N;x1++)
{
 for(int x2=x1;x2<=N;x2++)
 {
   memset(memy,0,MAX);
memy[1]=subMatrix(x1,1,x2,1);
posybegin[1]=1;
int max=INT_MIN;
int y1,y2;
for(int y=2;y<=M;y++)
{
if(memy[y-1]<0){
 memy[y]=subMatrix(x1,y,x2,y);
     posybegin[y]=y;
}
else
{
 memy[y]=subMatrix(x1,y,x2,y)+memy[y-1];
 posybegin[y]=posybegin[y-1];
}
}
        for(int r=1;r<=M;r++)
{
 if(memy[y]>max)
 {
   max=memy[y];
y1=posybegin[y];
y2=y;
 }
}
if(max>Max)
{
 Max=max;
 posx1=x1;
 posx2=x2;
 posy1=y1;
 posy2=y2;
}
 }
}
cout<<Max<<endl;
cout<<“(“<<posx1<<“,”<<posy1<<“)”<<endl;
cout<<“(“<<posx2<<“,”<<posy2<<“)”<<endl;
  }
  return 0;
}

拓展题待续~

    原文作者:快乐的霖霖
    原文地址: https://blog.csdn.net/chdhust/article/details/8282060
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞