【SCOI2005】 最大子矩阵 BZOJ 1084
Description
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
Input
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
Output
只有一行为k个子矩阵分值之和最大为多少。
Sample Input
3 2 2
1 -3
2 3
-2 3
1 -3
2 3
-2 3
Sample Output
9
思路
看到题目:好难啊。。一点思路都没有。
然后看到数据范围M<=2,你™在逗我?何必用矩形来吓人呢。。就是两个一维的最大子矩阵问题嘛!
然后用f[i][j][k]表示第一列用到i,第二列用到j,已经有k个矩形的最大值。
所以f[i][j][k]=max{f[i'-1][j][k-1]+sum[1][i'][i],f[i][j'-1][k-1]+sum[2][j'][j]}
当i==j的时候还会有一个转移,就是两行一起形成一个矩形。
f[i][i][k]=max{f[i'-1][i'-1][k-1]+sum[1][i'][i]+sum[2][i'][i]}
其中sum[i][j][k]表示第i列从第j个数加到第k个数的和。
还有一种特殊情况就是全都是负数,或者非负数的个数不够k的,就先选出所有的非负数,然后加上最大的几个负数就行了。
可是数据里面好像没有这种情况TAT。。伐开森。
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <cmath> 7 #include <algorithm> 8 #include <queue> 9 #include <stack> 10 #include <map> 11 #include <set> 12 #include <list> 13 #include <vector> 14 #include <ctime> 15 #include <functional> 16 #define pritnf printf 17 #define scafn scanf 18 #define sacnf scanf 19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++) 20 #define Clear(a) memset(a,0,sizeof(a)) 21 using namespace std; 22 typedef unsigned int Uint; 23 const int INF=0x3fffffff; 24 ///==============struct declaration============== 25 26 ///==============var declaration================= 27 const int MAXN=110; 28 int row,col,k,temp=0; 29 int A[MAXN][10],Sum[MAXN][5]; 30 int f[MAXN][MAXN][15]; 31 ///==============function declaration============ 32 int cmp(int a,int b){return a>b;} 33 ///==============main code======================= 34 int main() 35 { 36 #define FILE__ 37 #ifdef FILE__ 38 freopen("input","r",stdin); 39 freopen("output","w",stdout); 40 #endif 41 scanf("%d%d%d",&row,&col,&k); 42 int Plus=0; 43 for(int i=1;i<=row;i++) 44 for(int j=1;j<=col;j++){ 45 scanf("%d",&A[i][j]); 46 Sum[i][j]=Sum[i-1][j]+A[i][j]; 47 if (A[i][j]>=0){ 48 Plus++; 49 temp+=A[i][j]; 50 } 51 } 52 for(int r1=1;r1<=row;r1++) 53 for(int r2=1;r2<=row;r2++) 54 for(int p=1;p<=k;p++){ 55 f[r1][r2][p]=max(f[r1][r2-1][p],f[r1-1][r2][p]); 56 for(int NewR=1;NewR<=max(r1,r2);NewR++){ 57 if (NewR<=r1) 58 f[r1][r2][p]=max(f[r1][r2][p],f[NewR-1][r2][p-1]+Sum[r1][1]-Sum[NewR][1]); 59 if (NewR<=r2) 60 f[r1][r2][p]=max(f[r1][r2][p],f[r1][NewR-1][p-1]+Sum[r2][2]-Sum[NewR][2]); 61 if (r1==r2){ 62 f[r1][r2][p]=max(f[NewR-1][NewR-1][p-1]+Sum[r1][1]-Sum[NewR][1]+Sum[r2][2]-Sum[NewR][2],f[r1][r2][p]); 63 } 64 } 65 } 66 if (Plus>=k) 67 printf("%d\n",f[row][row][k]); 68 else{ 69 int Arr[MAXN*2]; 70 for(int i=1;i<=row;i++){ 71 Arr[i*2-1]=A[i][1];if (Arr[i*2-1]>0) Arr[i*2-1]=-INF; 72 Arr[i*2]=A[i][2];if (Arr[i*2]>0) Arr[i*2]=-INF; 73 } 74 sort(Arr+1,Arr+1+row*2,cmp); 75 for(int i=Plus+1;i<=k;i++) 76 temp+=Arr[i-Plus]; 77 printf("%d\n",temp); 78 } 79 return 0; 80 } 81 ///================fuction code====================