• [SCOI2009]粉刷匠(分组背包)


    Problem

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

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

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

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

    Solution

    很容易发现这是一道背包问题。

    我们发现一共有n条木板,每个木板之间没有关系,所以我们可以想到用分组背包。

    设子状态$dp[i][j]$代表处理到第i组刷j次最多能粉刷对多少格子。

    有组之间的转移方程$dp[i][j] = max(dp[i-1][j], dp[i-1][j-k]+val(i,k))$

    其中$val(i,k)$代表第i个木板刷k次所能刷对的最多格子数。

    现在考虑如何求出$val(i,k)$。我们发现只有一维次数是肯定不行的,得再加一维代表刷1-j的格子。

    所以我们得到了组内价值的子状态:$f[i][j][k]$代表刷第i个木板的1-i,刷k次能刷对的最大格子数,显然i那一维是可以省略的。

    有转移方程$f[j][k] = max(f[j][k], f[l][k-1]+max(val2(l+1, j, 1), val2(l+1, j, 0)))$,其中$val2(x, y, u)$代表从x到y全部刷u能刷对的最大格子数。

    val2可以用前缀和做到。

    然后这道题就迎刃而解了。

    Code

    /*
    dp[i][j] 代表前 i 个木板,粉刷 j 次可以粉刷正确的次数 
    
    dp[i][j] = max(dp[i-1][j], dp[i-1][j-k]+f[m][k]);
    
    这里又要引入一个数组 f  
    
    f[i][j] 代表位置从 1 到 i 粉刷 j 次的最大粉刷正确次数 
    
    对于每一组 f 都是不一样的,要从新求 
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int N, M, T;
    char s[55];
    int dp[55][2510];
    int f[55][55];
    int sum[55];
    int ans;
    int main() {
        scanf("%d%d%d", &N, &M, &T);
        for (int i = 1; i <= N; i++) {
            scanf("%s", s + 1);
            for (int j = 1; j <= M; j++) {
                sum[j] = sum[j - 1] + s[j] - '0';
            }
            //因为每个格子只能被刷一遍,所以每次被刷的次数只会到 m  
            for (int t = 1; t <= M; t++) {
                for (int j = 1; j <= M; j++) {
                    f[j][t] = 0;//初始化为 0  
                    for (int k = 0; k < j; k++) {
                        //计算 f[j][t] 
                        f[j][t] = max(f[j][t], f[k][t - 1] + max((sum[j] - sum[k]), j - k - (sum[j] - sum[k])));
                    }
                }
            }
            for (int t = 1; t <= T; t++) {
                for (int j = 1; j <= min(M, t); j++) {
                    dp[i][t] = max(dp[i][t], dp[i - 1][t - j] + f[M][j]);
                    ans = max(ans, dp[i][t]);
                }
            }
        }
        cout << ans;
        return 0;
    } 
  • 相关阅读:
    Linux基础之计算机硬件
    python中 __cmp__
    python中 __str__和__repr__
    python的构造函数传入任意数量的参数
    python中的偏函数
    javascript正则表达式
    js实现复选框的全选、全部选和反选
    js中的函数对象
    js中的作用域
    js中的arguments
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12989068.html
Copyright © 2020-2023  润新知