题目描述
有一个包含正数和负数的二维数组。一个子矩阵是指在该二维数组里,任意相邻的下标是1*1或更大的子数组。一个子矩阵的和是指该子矩阵中所有元素的和。本题中,把具有最大和的子矩阵称为最大子矩阵。
例如:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
这个数组的最大子矩阵为:
9 2
-4 1
-1 8
其和为15。
输入
输入包含多组测试数据。每组输入的第一行是一个正整数N(1<=N<=100),表示二维方阵的大小。接下来N行每行输入N个整数,表示数组元素,范围为[-127,127]。
输出
输出最大子阵和。
思路:
我们假设所求N*N的矩阵的最大子矩阵是从i列到j列,q行到p行,如下图所示(假设下标从1开始)
a[1][1] a[1][2] ······ a[1][i] ······ a[1][j] ······ a[1][n]
a[2][1] a[2][2] ······ a[2][i] ······ a[2][j] ······ a[2][n]
······
a[q][1] a[q][2] ······ a[q][i] ······ a[q][j] ······ a[q][n]
······
a[p][1] a[p][2] ······ a[p][i] ······ a[p][j] ······ a[p][n]
······
a[n][1] a[n][2] ······ a[n][i] ······ a[n][j] ······ a[n][n]
最大子矩阵就是图示红色部分,如果把最大子矩阵同列的加起来,我们可以得到一个一维数组{a[q][i]+······+a[p][i] , ······ ,a[q][j]+······+a[p][j]} ,现在我们可以看出,这其实就是一个一维数组的最大子段问题。如果把二维数组看成是纵向的一维数组和横向的一维数组,那问题不就迎刃而解了吗?把二维转换成了我们刚刚解决了的问题。
代码
1 #include <iostream>
2 #include <cstring>
3 using namespace std;
4
5 int maxsub(int a[],int n)
6 {
7 int i,max=0,b=0;
8 for(i=0;i<n;i++)
9 {
10 if(b > 0)
11 b += a[i];
12 else
13 b = a[i];
14 if(b > max)
15 max = b;
16 }
17 return max;
18 }
19
20 int main()
21 {
22 int n,i,j,k,maxsubrec,maxsubarr;
23 int dp[101][101],arr[101];
24 while(cin>>n)
25 {
26 for(i=0;i<n;i++)
27 for(j=0;j<n;j++)
28 cin>>dp[i][j];
29 maxsubrec = 0;
30 for(i=0;i<n;i++)
31 {
32 memset(arr,0,sizeof(arr));
33 for(j=i;j<n;j++)
34 {
35 for(k=0;k<n;k++)
36 arr[k] += dp[j][k];
37 maxsubarr = maxsub(arr,n);
38 if(maxsubarr > maxsubrec) maxsubrec = maxsubarr;
39 }
40 }
41 cout<<maxsubrec<<endl;
42 }
43 }