To the Max
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 39913 | Accepted: 21099 |
Description
Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
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.
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.
Input
The
input consists of an N * N array of integers. The input begins with a
single positive integer N on a line by itself, indicating the size of
the square two-dimensional array. This is followed by N^2 integers
separated by whitespace (spaces and newlines). These are the N^2
integers of the array, presented in row-major order. That is, all
numbers in the first row, left to right, then all numbers in the second
row, left to right, etc. N may be as large as 100. The numbers in the
array will be in the range [-127,127].
Output
Output the sum of the maximal sub-rectangle.
Sample Input
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
Sample Output
15
Source
这是hdu 1003的拓展,知道了在一维数组中如何求最大连续子段和,那么这题就是扩展到二维数组中,让我们求出子矩阵最大的和,我们可以这样考虑,我们把同行不同列(或者同列不同行)的加起来,比如i行,j行,i,j两行之间的数字组成了一个矩阵,我们把i行到j行之间同列的数组元素加起来按照列号组成一个一维数组,这样我们只需要利用最大子段和的知识找出这个数组的最大连续和,这个和就是我们要求的那个子矩阵最大和! 可以说, i和j行定义了子矩阵高度,一维数组最大子段和连续的长度定义了子矩阵的宽度,OK,代码。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 int temp[101],n; 7 int cal() // 8 { 9 int Max = temp[0]; 10 int sum = temp[0]; 11 for(int i =1 ;i<n;i++) 12 { 13 if(sum+temp[i]<temp[i]) 14 sum = temp[i]; 15 else 16 sum+=temp[i]; 17 if(Max<sum) 18 Max = sum; 19 } 20 return Max; 21 } 22 23 int main() 24 { 25 while(scanf("%d",&n)!=EOF) 26 { 27 int a[101][101]; 28 for(int i = 0;i<n;i++) 29 for(int j =0 ;j<n;j++) 30 scanf("%d",&a[i][j]); 31 int Max = 0; 32 for(int i =0 ;i< n;i++) //i是起始行 33 { 34 for(int j =i ;j<n;j++) //j是终止行 35 { 36 memset(temp,0,sizeof(temp)); 37 for(int m = 0;m<n;m++) //固定列,注意是行在变 38 { 39 for(int k =i ;k<=j;k++) //累加i起始行,j终止行中间的同列的数据 40 temp[m]+=a[k][m]; 41 } 42 int MaxTemp = cal(); 43 if(MaxTemp>Max) 44 Max = MaxTemp; 45 } 46 47 } 48 printf("%d ",Max); 49 } 50 return 0; 51 }
事实证明我蠢了,后来看到nyoj这题的最优程序解答,在处理第i行到j行同列相加上面处理的很好,利用输入时候进行累加,然后做减法,直接减掉了一层循环
nyoj 的版本
1 2 3 #include<iostream> 4 #include<cstring> 5 using namespace std; 6 #define N 110 7 int a[N][N]; 8 int b[N]; 9 int main() 10 { 11 int n,r,c; 12 cin>>n; 13 while(n--) 14 { 15 cin>>r>>c; 16 for(int i=1;i<=r;++i) 17 for(int j=1;j<=c;++j) 18 { 19 cin>>a[i][j]; 20 a[i][j]+=a[i-1][j]; 21 } 22 int max=a[1][1]; 23 for(int i=0;i<=r-1;++i) 24 for(int j=i+1;j<=r;++j) 25 { 26 memset(b,0,sizeof(b)); 27 for(int k=1;k<=c;++k) 28 { 29 if(b[k-1]>=0) 30 b[k]=b[k-1]+a[j][k]-a[i][k]; 31 else 32 b[k]=a[j][k]-a[i][k]; 33 if(max<b[k]) 34 max=b[k]; 35 } 36 } 37 cout<<max<<endl; 38 } 39 }
还有一种没有用这种求和的方法,但是是先求第一行最大子段和,再求第一行跟第二行合起来的最大子段和,,再求第一到第三合起来的最大子段和,以此类推,直到求出整个矩阵的合起来的最大子段和,最后就是我们需要的解 。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 int temp[101],n; 7 int cal() //最大子段和 8 { 9 int Max = temp[0]; 10 int sum = temp[0]; 11 for(int i =1 ;i<n;i++) 12 { 13 if(sum+temp[i]<temp[i]) 14 sum = temp[i]; 15 else 16 sum+=temp[i]; 17 if(Max<sum) 18 Max = sum; 19 } 20 return Max; 21 } 22 23 int main() 24 { 25 while(scanf("%d",&n)!=EOF) 26 { 27 int a[101][101]; 28 for(int i = 0;i<n;i++) 29 for(int j =0 ;j<n;j++) 30 scanf("%d",&a[i][j]); 31 int Max = 0; 32 for(int i =0 ;i< n;i++) 33 { 34 memset(temp,0,sizeof(temp)); 35 for(int j =i ;j<n;j++) 36 { 37 for(int k =0 ;k<n;k++) 38 temp[k]+=a[j][k]; 39 int t = cal(); 40 if(t>Max) 41 Max =t; 42 } 43 44 } 45 printf("%d ",Max); 46 } 47 return 0; 48 }