To The Max
Total Submission(s): 8989 Accepted Submission(s): 4356
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
15
//常见的矩阵压缩,将二维的矩阵压缩成一维矩阵,然后按照最大子序列问题来处理
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int a[110][110];
int dp[10010];
int main()
{
int n;
while(~scanf("%d",&n))
{
int i,j,k,M;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
M=-1000000;
for(i=1;i<=n;i++)
{
memset(dp,0,sizeof(dp));
for(j=i;j<=n;j++)
{
for(k=1;k<=n;k++)
dp[k]+=a[j][k];
int sum=0;
for(k=1;k<=n;k++)//这部分就是传说中的最大子序列问题常见算法
{
if(sum>0)
sum+=dp[k];
else
sum=dp[k];
if(sum>M)
M=sum;
}
}
}
printf("%d\n",M);
}
return 0;
}
//
其他的人算法:感觉挺高深的
常见的矩阵压缩,将二维的矩阵压缩成一维矩阵,然后按照最大子序列问题来处理
扩展到二维的时候也是同样的方法,不过需要将二维压缩成一维,所以我们要将数据做一下处理,使得map[i][j]从表示第i行第j个元素变成表示第i行前j个元素和,这样map[k][j]-map[k][i]就可以表示第k行从i->j列的元素和。只要比一维多两层循环枚举i和j就行了。
#include <iostream>
#define MAX 101using namespace std;
int map[MAX][MAX];
int main()
{
int n, i, j, temp, k;
while(scanf("%d", &n) != EOF)
{
memset(map, 0, sizeof(map));
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
{
scanf("%d", &temp);
map[i][j] += map[i][j - 1] + temp;//这里表示第i行的前j列之和
}
int max = -100000;
for(i = 1; i <= n; i++)
for(j = i; j <= n; j++)
{
int sum = 0;
for(k = 1; k <= n; k++)
{
if(sum < 0)
sum = 0;
sum += map[k][j] - map[k][i - 1];//这里表示前k行,i->j列之和
if(sum > max)
max = sum;
}
}
printf("%d\n", max);
}
return 0;
}