1. 程式人生 > >luogu P2331 [SCOI2005]最大子矩陣 序列DP

luogu P2331 [SCOI2005]最大子矩陣 序列DP

can cst code 一段 string 價值 狀態 方程 %d

我們觀察到m非常小。

考慮只有一行的情況,dp[i][o]表示[1,i]這一段中取出o個矩形,的最大價值。我們預處理出w[i][j]表示[i,j]這一段的最大子矩陣 。那麽轉移非常顯然。

dp[i][o] = max(dp[j - 1][o] + w[j][i])

我們接著考慮兩行的情況,我們類比一下,用dp[i][j][o]表示第一行[1,i],第二行[1,j],一共選了o個子矩陣的最大價值。同時預處理出w[i][j][0],表示[i,j]這一段高為2的最大子矩陣,w[i][j][1],表示[i,j]這一段,上面一行的最大子矩陣,w[i][j][2]表示[i,j]這一段的下面一行的最大子矩陣。那麽我們考慮對於dp[i][j][o],我們無非是從一個狀態第一行取了一個子矩陣,得到,第二行去了一個子矩陣得到,取了一個高為2的子矩陣得到。那麽轉移依舊很顯然,dp[i][j][o] = max(dp[u - 1][j][o] + w[u][j][1]) dp[i][j][o] = max(dp[i][u - 1][o] + w[u][j][2]) dp[i][j][o] = max(dp[u - 1][u - 1][o] + w[u][min(i,j)][0])三個轉移方程。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <queue>
 7 using namespace std;
 8 int n,m,k;
 9 int vec[110][3],w[110][110],w1[110][110][3],dp[110][15],dp1[110][110][15];
10 int main()
11
{ 12 scanf("%d%d%d",&n,&m,&k); 13 for (int i = 1;i <= n;i++) 14 for (int j = 1;j <= m;j++) 15 scanf("%d",&vec[i][j]); 16 for (int i = 1;i <= n;i++) 17 vec[i][0] = vec[i][1] + vec[i][2]; 18 if (m == 1) 19 { 20 for
(int i = 1;i <= n;i++) 21 { 22 int tp = 0; 23 for (int j = i;j <= n;j++) 24 { 25 tp = max(tp + vec[j][1],0); 26 w[i][j] = max(w[i][j - 1],tp); 27 } 28 } 29 // 30 for (int o = 1;o <= k;o++) 31 for (int i = 1;i <= n;i++) 32 for (int j = o;j <= i;j++) 33 dp[i][o] = max(dp[j - 1][o - 1] + w[j][i],dp[i][o]); 34 printf("%d\n",dp[n][k]); 35 }else 36 { 37 for (int o = 0;o <= 2;o++) 38 for (int i = 1;i <= n;i++) 39 { 40 int tp = 0; 41 for (int j = i;j <= n;j++) 42 { 43 tp = max(tp + vec[j][o],0); 44 w1[i][j][o] = max(w1[i][j - 1][o],tp); 45 } 46 } 47 for (int o = 1;o <= k;o++) 48 for (int i = 1;i <= n;i++) 49 for (int j = 1;j <= n;j++) 50 { 51 for (int u = 1;u <= i;u++) 52 dp1[i][j][o] = max(dp1[u - 1][j][o - 1] + w1[u][i][1],dp1[i][j][o]); 53 for (int u = 1;u <= j;u++) 54 dp1[i][j][o] = max(dp1[i][u - 1][o - 1] + w1[u][j][2],dp1[i][j][o]); 55 for (int u = 1;u <= min(i,j);u++) 56 dp1[i][j][o] = max(dp1[u - 1][u - 1][o - 1] + w1[u][min(i,j)][0],dp1[i][j][o]); 57 } 58 printf("%d\n",dp1[n][n][k]); 59 } 60 return 0; 61 }

luogu P2331 [SCOI2005]最大子矩陣 序列DP