洛谷P2331 [SCOI2005]最大子矩阵
? 解题记录 ? ? 洛谷 ? ? 动态规划 ?    2017-10-19 13:37:48    779    0    0

题目描述

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。

输入输出格式

输入格式:

 

第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

 

输出格式:

 

只有一行为k个子矩阵分值之和最大为多少。

 

输入输出样例

输入样例#1:
3 2 2
1 -3
2 3
-2 3
输出样例#1:
9​​

 

一开始看到这道题是很懵逼的,但是仔细看数据貌似m最大只有2?

那当然就可以dp了呀。不过是线性区间取数的加强版。

接下来我们考虑状态,用dp[i][j][k]表示第i行,取了j个矩阵。其中k表示当前状态的一些操作:(用x表示取,o表示不取)xo(10), ox(01), xx(11), oo(00)。

考虑状态转移:以xo的情况为例:

xo ox xx oo
xo xo xo xo
1  2  3  4

可是问题就来了,1、2、4状态都很好转移,但是3的转移举步维艰。为了能顺利的转移,我们再引入一个新的状态(Xx 100) 表示现在选取的两个数左右分别一个矩形,并且用原来的xx表示现在选的两个数在同一个矩形。代码就写好了(极长的状态转移):

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ox 1
#define xo 2
#define oo 0
#define xx 3
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[105][12][4], n, m, k, mp[105][2], tmp[2][4], mx;
int main() {
    scanf("%d%d%d", &n, &m, &k);
    for(register int i = 1; i <= n; ++i)
        for(register int j = 0; j < m; ++j)
            scanf("%d", &mp[i][j]);
    if(m == 2) {
        dp[1][0][oo] = dp[1][0][ox] = dp[1][0][xo] = dp[1][0][xx] = 0;
        dp[1][1][oo] = 0;
        dp[1][1][ox] = mp[1][1];
        dp[1][1][xo] = mp[1][0];
        dp[1][1][xx] = mp[1][1] + mp[1][0];
        for(register int j = 1; j <= k; ++j)
                printf("%d %d, oo : %d xx : %d xo : %d ox : %d\n", 1, j, dp[1][j][oo], dp[1][j][xx], dp[1][j][xo], dp[1][j][ox]);
        for(register int i = 2; i <= n; ++i) {
            for(register int j = 1; j <= k; ++j)    {
                if(j) {
                    tmp[0][oo] = dp[i - 1][j - 1][oo];
                    tmp[0][xx] = dp[i - 1][j - 1][xx];
                    tmp[0][xo] = dp[i - 1][j - 1][xo];
                    tmp[0][ox] = dp[i - 1][j - 1][ox];
                }else
                tmp[0][oo] = tmp[0][xx] = tmp[0][xo] = tmp[0][ox] = -inf;
                
                tmp[1][oo] = dp[i - 1][j][oo];
                tmp[1][xx] = dp[i - 1][j][xx];
                tmp[1][xo] = dp[i - 1][j][xo];
                tmp[1][ox] = dp[i - 1][j][ox];
                dp[i][j][oo] = max(max(tmp[1][oo], 
                                       tmp[1][xx]),
                                   max(tmp[1][ox], 
                                       tmp[1][xo]));
                dp[i][j][xx] = max(max(tmp[0][oo], 
                                       tmp[1][xx]),
                                   max(tmp[0][ox], 
                                       tmp[0][xo])) + mp[i][0] + mp[i][1];
                dp[i][j][ox] = max(max(tmp[0][oo], 
                                       tmp[0][xx]),
                                   max(tmp[1][ox], 
                                       tmp[0][xo])) + mp[i][1];
                dp[i][j][xo] = max(max(tmp[0][oo], 
                                       tmp[0][xx]),
                                   max(tmp[0][ox], 
                                       tmp[1][xo])) + mp[i][0];
            }
            for(register int j = 1; j <= k; ++j)
                printf("%d %d, oo : %d xx : %d xo : %d ox : %d\n", i, j, dp[i][j][oo], dp[i][j][xx], dp[i][j][xo], dp[i][j][ox]);
        }
        for(register int i = 0; i <= k; ++i)
            mx = max(mx, max(max(dp[n][k][oo], dp[n][k][xx]), max(dp[n][k][ox], dp[n][k][xo])));
        printf("%d\n", mx);
        return 0;
    }
    dp[1][1][xo] = mp[1][0];
    for(register int i = 2; i <= n; ++i) {
        for(register int j = 1; j <= k; ++j)    {
            if(j) {
                tmp[0][oo] = dp[i - 1][j - 1][oo];
                tmp[0][xo] = dp[i - 1][j - 1][xo];
            }else {
                tmp[0][oo] = tmp[0][xo] = -inf;
            }
            tmp[1][oo] = dp[i - 1][j][oo];
            tmp[1][xo] = dp[i - 1][j][xo];
            dp[i][j][oo] = max(tmp[1][oo], tmp[1][xo]);
            dp[i][j][xo] = max(tmp[0][oo], tmp[1][xo]) + mp[i][0];
            mx = max(mx, max(dp[i][j][xo], dp[i][j][oo]));
        }
        for(register int j = 0; j <= k; ++j)
                printf("%d %d, oo : %d xx : %d xo : %d ox : %d\n", i, j, dp[i][j][oo], dp[i][j][xx], dp[i][j][xo], dp[i][j][ox]);
    }
    printf("%d\n", mx);
    return 0;
}

 

上一篇: 洛谷P1991 无线通讯网

下一篇: 洛谷P2216 [HAOI2007]理想的正方形

779 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航