1. 程式人生 > >bzoj1084 [SCOI2005]最大子矩陣

bzoj1084 [SCOI2005]最大子矩陣

inline dp2 轉移 mat ace end char 相互 nbsp

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

Sample Output

9

正解:$dp$。

首先註意到一個性質:$m\leq 2$。

那麽我們可以考慮一下,每次一個子矩陣要麽只在第一列,要麽只在第二列,要麽橫跨兩列。

那麽我們可以設$f[i][j][k]$表示第一列到$i$,第二列到$j$,取了$k$個子矩陣的最大值,轉移比較簡單,不過註意第三種情況只有$i=j$時才能轉移。

$m=1$時同理,就是把$f[i][j][k]$換成$f[i][k]$就行了。

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define inf (1<<30)
 6
7 using namespace std; 8 9 int sum[110][2],g[110][2],n,m,k; 10 11 il int gi(){ 12 RG int x=0,q=1; RG char ch=getchar(); 13 while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 14 if (ch==-) q=-1,ch=getchar(); 15 while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar();
16 return q*x; 17 } 18 19 namespace dp1{ 20 21 int f[110][12]; 22 23 int main(){ 24 for (RG int i=0;i<=n;++i) 25 for (RG int j=1;j<=k;++j) f[i][j]=-inf; 26 for (RG int i=1;i<=n;++i) 27 for (RG int j=1;j<=k;++j){ 28 f[i][j]=max(f[i][j],f[i-1][j]); 29 for (RG int p=0;p<i;++p) 30 f[i][j]=max(f[i][j],f[p][j-1]+sum[i][1]-sum[p][1]); 31 } 32 cout<<f[n][k]; return 0; 33 } 34 35 } 36 37 namespace dp2{ 38 39 int f[110][110][12]; 40 41 int main(){ 42 for (RG int i=0;i<=n;++i) 43 for (RG int j=0;j<=n;++j) 44 for (RG int p=1;p<=k;++p) f[i][j][p]=-inf; 45 for (RG int i=1;i<=n;++i) 46 for (RG int j=1;j<=n;++j) 47 for (RG int p=1;p<=k;++p){ 48 f[i][j][p]=max(f[i][j][p],f[i-1][j][p]); 49 f[i][j][p]=max(f[i][j][p],f[i][j-1][p]); 50 for (RG int pre=0;pre<i;++pre) 51 f[i][j][p]=max(f[i][j][p],f[pre][j][p-1]+sum[i][1]-sum[pre][1]); 52 for (RG int pre=0;pre<j;++pre) 53 f[i][j][p]=max(f[i][j][p],f[i][pre][p-1]+sum[j][2]-sum[pre][2]); 54 if (i==j) 55 for (RG int pre=0;pre<i;++pre) 56 f[i][j][p]=max(f[i][j][p],f[pre][pre][p-1]+sum[i][1]-sum[pre][1]+sum[j][2]-sum[pre][2]); 57 } 58 cout<<f[n][n][k]; return 0; 59 } 60 61 } 62 63 int main(){ 64 #ifndef ONLINE_JUDGE 65 freopen("matrix.in","r",stdin); 66 freopen("matrix.out","w",stdout); 67 #endif 68 n=gi(),m=gi(),k=gi(); 69 for (RG int i=1;i<=n;++i) 70 for (RG int j=1;j<=m;++j) g[i][j]=gi(); 71 for (RG int i=1;i<=n;++i){ 72 sum[i][1]=sum[i-1][1]+g[i][1]; 73 sum[i][2]=sum[i-1][2]+g[i][2]; 74 } 75 if (m==1) dp1::main(); 76 if (m==2) dp2::main(); 77 return 0; 78 }

bzoj1084 [SCOI2005]最大子矩陣