洛谷 2331 [SCOI2005]最大子矩阵

现在的题都好难啊

看题

这道题我一开始觉得很简单写了一个小时,发现自己写了一个错的算法

于是看了看题解

发现并没有这么简单

我来讲解一下

看到了m的范围

1<=m<=2

如果m=1,这题就很简单了,就是求k个最大子段和

这里可以分开来讨论

m=1时的dp方程就是

dp[i][j][1]=max(dp[i-1][j-1][0],dp[i-1][j][1])+x;
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);

最后取两个max

 

如果m=2时怎么办呢?

设dp[i][j][0~4],表示到了i,j位置,0~4操作能获得的最大值

0操作是当前这一排什么都不取

1操作是当前这一排取左边的一块,空出了右边

2操作是当前这一排取右边的一块,空出了左边

3操作是当前这一排的左右,但是左右两列分别成块

4操作是取当前这一排,左右都成为一块

接下来是dp的转移

dp[i][j][0]=max(max(dp[i-1][j][0],dp[i-1][j][1]),max(dp[i-1][j][2],dp[i-1][j][3]));
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][4]);

当前是0,则是承接上一个状态的最大值

 

dp[i][j][1]=max(max(dp[i-1][j-1][0],dp[i-1][j][1]),max(dp[i-1][j-1][2],dp[i-1][j][3]))+x;
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-1][4]+x);

当前是1,则可以合并上一个状态的操作1,和操作3,再取所有操作的最大值,最后加上当前位置的值


dp[i][j][2]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),max(dp[i-1][j][2],dp[i-1][j][3]))+y;
dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-1][4]+y);

当前是2,则可以合并上一个状态的操作2,和操作3,再取所有操作的最大值,最后加上当前位置的值

 

dp[i][j][3]=max(dp[i-1][j-1][1],max(dp[i-1][j-1][2],dp[i-1][j][3]))+x+y;
if(j>=2)
dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-2][4]+x+y);

当前是3,则可以合并合并上一个状态的3,左边和右边取一个max,在加上max位置的值


dp[i][j][4]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),max(dp[i-1][j-1][2],dp[i-1][j-1][3]))+x+y;
dp[i][j][4]=max(dp[i][j][4],dp[i-1][j][4]+x+y);

当前是4,则只能合并上一个状态的4,在与所有的取max,在加上这一排的数

最后所有的操作取max

贴上我的代码

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cstring>
 6 using namespace std;
 7 const int N=105;
 8 int dp[N][N][10],x,y,n,m,K;
 9 int main()
10 {
11     scanf("%d %d %d",&n,&m,&K);
12     if(m==1)
13     {
14         for(int i=1;i<=n;i++)
15         {
16             scanf("%d",&x);
17             for(int j=1;j<=K;j++)
18             {
19                 dp[i][j][1]=max(dp[i-1][j-1][0],dp[i-1][j][1])+x;
20                 dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);
21                 
22             }
23         }
24         printf("%d\n",max(dp[n][K][0],dp[n][K][1]));
25         return 0;
26     }
27     else
28     {
29         memset(dp,-0x3f,sizeof(dp));
30         for(int i=0;i<=n;i++)
31             for(int j=0;j<=K;j++)
32                 dp[i][j][0]=0;
33         for(int i=1;i<=n;i++)
34         {
35             scanf("%d %d",&x,&y);
36             for(int j=1;j<=K;j++)
37             {
38                 dp[i][j][0]=max(max(dp[i-1][j][0],dp[i-1][j][1]),max(dp[i-1][j][2],dp[i-1][j][3]));
39                 dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][4]);
40 
41 
42                 dp[i][j][1]=max(max(dp[i-1][j-1][0],dp[i-1][j][1]),max(dp[i-1][j-1][2],dp[i-1][j][3]))+x;
43                 dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-1][4]+x);
44 
45 
46                 dp[i][j][2]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),max(dp[i-1][j][2],dp[i-1][j][3]))+y;
47                 dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-1][4]+y);
48 
49                 dp[i][j][3]=max(dp[i-1][j-1][1],max(dp[i-1][j-1][2],dp[i-1][j][3]))+x+y;
50                 if(j>=2)
51                     dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-2][4]+x+y);
52 
53 
54                 dp[i][j][4]=max(max(dp[i-1][j-1][0],dp[i-1][j-1][1]),max(dp[i-1][j-1][2],dp[i-1][j-1][3]))+x+y;
55                 dp[i][j][4]=max(dp[i][j][4],dp[i-1][j][4]+x+y);
56             }
57         }
58         int ans=max(max(dp[n][K][0],dp[n][K][1]),max(dp[n][K][2],dp[n][K][3]));
59         ans=max(ans,dp[n][K][4]);
60         printf("%d\n",ans);
61     }
62     return 0;
63 }

 

posted @ 2018-10-17 10:59  没有名字的大佬  阅读(173)  评论(0编辑  收藏  举报