bzoj1296 [SCOI2009]粉刷匠——背包

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1296

对于不同木板之间,最终统计答案时做一个分组背包即可;

而要进行分组背包,就需要知道每个木板被刷几次的最大正确格子数;

所以对于每个木板分别DP,状态 f[i][j] 定义为前 i 个格子刷 j 次的最大正确格子数;

转移时枚举断点,从那以后刷一个颜色,带上新加入的这个点,就可以进行DP了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,t,f[55][2505],s1[55],s0[55],ans,dp[55][2505];
int main()
{
    scanf("%d%d%d",&n,&m,&t);
    for(int i=1;i<=n;i++)
    {
        memset(f,0,sizeof f);
        memset(s1,0,sizeof s1);
        memset(s0,0,sizeof s0);
        for(int j=1,x;j<=m;j++)
        {
            scanf("%1d",&x);
            s1[j]=s1[j-1];s0[j]=s0[j-1];
            if(x)s1[j]++; else s0[j]++;
            for(int k=1;k<=min(j,t);k++)//次数 
                for(int l=0;l<j;l++)//断点 
                    f[j][k]=max(f[j][k],f[l][k-1]+max(s1[j]-s1[l],s0[j]-s0[l]));
        }
        for(int j=1;j<=t;j++)//次数 
            for(int k=0;k<=j&&k<=m;k++)//给i的次数 
                dp[i][j]=max(dp[i][j],dp[i-1][j-k]+f[m][k]);
    }
    for(int i=1;i<=t;i++)ans=max(ans,dp[n][i]);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9146974.html