A problem that is simple to solve in one dimension is often much more difficult to solve in more than one dimension. Consider satisfying a boolean expression in conjunctive normal form in which each conjunct consists of exactly 3 disjuncts. This problem (3-SAT) is NP-complete. The problem 2-SAT is solved quite efficiently, however. In contrast, some problems belong to the same complexity class regardless of the dimensionality of the problem. Given a 2-dimensional array of positive and negative integers, find the sub-rectangle with the largest sum. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the subrectangle with the largest sum is referred to as the maximal sub-rectangle. A sub-rectangle is any contiguous sub-array of size 1 × 1 or greater located within the whole array. 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-hand corner: 9 2
−4 1
−1 8 and has the 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 N2 integers separated by white-space (newlines and spaces). These N2 integers make up the array in row-major order (i.e., all numbers on the first row, left-to-right, then all numbers on 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 The output is the sum of the maximal sub-rectangle.
Sample Input
0 −2 −7 0
9 2 −6 2
−4 1 −4 1
−1 8 0 −2
Sample Output
15
题意:从所给的 N × N 的矩阵中选出任意矩阵,使其中的元素和最大
思路:
枚举i、j,然后对j进行降维压缩,再对降维后的一维数组求最大子序列(利用动态规划)即可。
(还看到一种写法,但是不是特别理解:枚举行区间,求出每列的和,再用d[i]=max(d[i-1]+sum[i],sum[i])动态规划公式,即可求出最大子矩阵和。)
降维压缩代码:
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 7 int a[220][220]; 8 int c[220]; 9 int dp[220]; 10 int main() 11 { 12 std::ios::sync_with_stdio(false); 13 int n; 14 cin>>n; 15 for(int i=0; i<n; i++) 16 { 17 for(int j=0; j<n; j++) 18 { 19 cin>>a[i][j]; 20 } 21 } 22 int ans=-inf; 23 for (int i=0; i<n; i++) //n行 24 { 25 memset(c,0,sizeof(c)); 26 for (int j=i; j<n; j++) //n行 27 { 28 //对i到j行矩阵进行降维操作 29 for (int k=0; k<n; k++) //n列 30 { 31 c[k]+=a[j][k]; 32 } 33 dp[0]=c[0];//对降维后的数组c[k]进行最大子序列和的动态规划 34 if (ans<dp[0]) 35 { 36 ans = dp[0]; 37 } 38 for(int k=1;k<n;k++)// n列 39 { 40 dp[k]=max(dp[k-1]+c[k],c[k]); 41 if (ans<dp[k]) 42 { 43 ans = dp[k]; 44 } 45 } 46 } 47 } 48 cout<<ans<<endl; 49 return 0; 50 }
不是特别理解的代码:
枚举行区间,求出每列的和,再用d[i]=max(d[i-1]+sum[i],sum[i])动态规划公式,即可求出最大子矩阵和。
1 #include<iostream> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 5 int a[220][220]; 6 int main() 7 { 8 std::ios::sync_with_stdio(false); 9 int n; 10 cin>>n; 11 for(int i=1; i<=n; i++) 12 { 13 for(int j=1; j<=n; j++) 14 { 15 cin>>a[i][j]; 16 a[i][j]+=a[i-1][j]; 17 } 18 }//每一行等于加上上面一行的和 19 int maxx=a[1][1]; 20 for(int i=0; i<=n; i++) 21 { 22 for(int j=i+1; j<=n; j++) 23 { 24 int sum=0; 25 for(int k=1;k<=n;k++) 26 { 27 sum+=a[j][k]-a[i][k]; 28 if(sum<0) 29 sum=0; 30 if(sum>maxx) 31 maxx=sum; 32 } 33 } 34 } 35 cout<<maxx<<endl; 36 37 38 return 0; 39 }