最大子矩阵和
分析: 我们已经解决了一维的问题(基础篇中的最大子段和问题),现在变成二维了,我们看看能不能把这个问题转化为一维的问题。最后子矩阵一定是在某两行之间的。假设我们认为子矩阵在第i行和第j列之间,我们如何得到i和j呢,对,枚举。 枚举所有1<=i<=j<=M,表示最终子矩阵选取的行范围。
1
2
3
4
5
6
7
8
9
for
i
=
1
to
M
do
for
j
=
i
to
M
do
//
计
算
第
每
列
第
i
行
到
第
j
列
的
和
for
k
=
1
to
N
do
c
[
k
]
=
(
j
==
i
)?
a
[
i
]
[
k
] :
(
c
[
k
]
+
a
[
j
]
[
k
])
endfor
//
求
c
的
最
大
子
段
和
记
录
全
局
最
优
结
果
endfor
endfor
最后,我们来提供输入输出数据,由你来写一段程序,实现这个算法,只有写出了正确的程序,才能继续后面的课程。
输出示例
输入
第1行:M和N,中间用空格隔开(2 <= M,N <= 500)。 第2 - N + 1行:矩阵中的元素,每行M个数,中间用空格隔开。(-10^9 <= M[i] <= 10^9)
输出
输出和的最大值。如果所有数都是负数,就输出0。
输入示例
3 3 -1 3 -1 2 -1 3 -3 1 2
输出示例
7
这个题是51NOD动态规划入门教程里的第一题。。。
代码:
#include<iostream>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
int flag;
int n,m;
long long maxx=-inf;
int del(long long c[])
{
int b=0,max1=0;
for(int i=0;i<m;i++)
{
if(b>0)
b+=c[i];
else
b=c[i];
if(b>max1)
max1=b;
}
return max1;
}
int main()
{
cin>>m>>n;
int a[505][505];
long long c[505];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cin>>a[i][j];
}
long long h;
flag=0;
for(int j=0;j<n;j++)
{
memset(c,0,sizeof(c));
for(int k=j;k<n;k++)
{
for(int i=0;i<m;i++)
{
c[i]+=a[k][i];
h=c[i];
}
if(h>0)
flag=1;
int l=del(c);
if(l>maxx)
maxx=l;
}
}
if(flag==0)
cout<<"0"<<endl;
else
cout<<maxx<<endl;
return 0;
}