P4158 [SCOI2009]粉刷匠(线性dp)

windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。

windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。

如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?

一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

思路:如果预先对所有木板进行处理(求出不同粉刷次数能得到的最大粉刷砖块数)好之后,就是分组背包问题了
而对木板如何预处理呢,答案是线性dp,具体看代码就行
2021/5/22更:重做了一遍,改了代码,之前的太冗杂了@_@
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1001000;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1000007;
int n, m, t;
int dp[55][55];
char s[55][55];
int res[maxn];
int main() {
    //freopen("test.txt", "r", stdin);
    scanf("%d%d%d", &n, &m, &t);
    for (int i = 1; i <= n; i++) {
        scanf("%s", s[i] + 1);
    }
    for (int q = 1; q <= n; q++) {
        memset(dp, 0, sizeof(dp));
        //dp[i][k],这一块板子的前i格粉刷k次能粉刷好的格子数
        for (int i = 1; i <= m; i++) {
            for (int k = 1; k <= i; k++) {
                int num1 = 0, num2 = 0;
                for (int j = i; j >= 1; j--) {//把(j-i)粉刷为数字最大的那个颜色
                    if (s[q][j] == '1') {
                        num1++;
                    }
                    else {
                        num2++;
                    }
                    dp[i][k] = max(dp[i][k], dp[j - 1][k - 1] + max(num1, num2));
                }
            }
        }
        for (int j = t; j >= 1; j--) {
            for (int i = 1; i <= min(m,j); i++) {//从当前板子选择一种粉刷次数来松弛
            res[j] = max(res[j], res[j - i] + dp[m][i]);
        }
       }
        /*for (int i = 1; i <= m; i++) {//反过来不对,这样就是用当前板子的所有粉刷次数来松弛,正确是只能选择一种粉刷次数来松弛
            for (int j = t; j >= i; j--) {
             res[j] = max(res[j], res[j - i] + dp[m][i]);
        }
       }*/
    }
    cout << res[t] << endl;
    return 0;
}

 


 
 
posted @ 2021-03-20 20:32  cono奇犽哒  阅读(72)  评论(0)    收藏  举报