最大和
时间限制:1000 ms | 内存限制:65535 KB
难度:5
- 描述
-
给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。
例子:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
其最大子矩阵为:9 2
-4 1
-1 8
其元素总和为15。- 输入
- 第一行输入一个整数n(0<n<=100),表示有n组测试数据;
每组测试数据:
第一行有两个的整数r,c(0<r,c<=100),r、c分别代表矩阵的行和列;
随后有r行,每行有c个整数;
- 输出
- 输出矩阵的最大子矩阵的元素之和。
- 样例输入
-
1 4 4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
- 样例输出
-
15
-
算法分析:二维数组求最大和,本题可以转换成为一维。
-
1. 将行划分,划分的结果为所有情况
2.将划分好的“新行”进行合并成“一行”,
3.对“一行”进行一维的求最大子段和
举个例子:
0 -2 -7 0
9 2 -6 2
-4 1 -4 7
-1 8 0 -2
我们分别用i j表示起始行和终止行,遍历所有的可能:
for(i=1;i<=n;i++)
for(j=i;j<=n;j++) {}
我们考察其中一种情况 i=2 j=4,这样就相当与选中了2 3 4三行,求那几列的组合能获得最大值,由于总是 2 3 4行,所以我们可以将这3行”捆绑”起来,变为求 4(9-4-1),11(8+2+1),-10(-6-4+0),7(7+2-2)的最大子段和,ok,问题成功转化为一维的情况!
注意:代码中还有一个地方需要注意,就是读入原始数据的时候,要处理一下,再保存到数组中,每一行的数据都不是原来的数据,而是加上同一列以上各行的数据,这样以来,在合并求和的时候就比较方便了。比如求2,3两行的和,只要第三行的值减去第一行的值就行了
-
#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <algorithm> using namespace std; int a[110][110], b[110]; #define mem(a) memset(a, 0, sizeof(a)) int Max_sum(int b[], int c) { int sum = 0, res = -9999999; for (int i = 1; i<=c; i++) { if (sum > 0) sum += b[i]; else sum = b[i]; if (sum > res) res = sum; } return res; } int main() { int t; scanf("%d",&t); while (t --) { mem(a); mem(b); int r, c; scanf("%d%d",&r, &c); for (int i = 1; i<=r; i++) { for (int j = 1; j<=c; j++) { scanf("%d",&a[i][j]); a[i][j] += a[i-1][j]; } } int res = -9999999; for (int i = 0; i<=r; i++) { for (int j = i+1; j<=r; j++) { for (int k = 1; k<=c; k++) { b[k] = a[j][k] - a[i][k]; } int Max = Max_sum(b, c); if (res < Max) res = Max; } } printf("%d ",res); } return 0; }