粉刷匠

粉刷匠

bzoj1296 粉刷匠 (洛谷P4158)

◦有n条木板要被粉刷,每条木板分为m个格子,每个格子需要被刷成蓝色

或红色。

◦每次粉刷可以在一条木板上给连续的一段格子刷上相同的颜色。每个格

子最多被刷一次。

◦问若只能刷k次,最多正确粉刷多少格子。

◦ n,m<=50,k<=2500

dp题。dp方程较难推,有两个dp值,包含了从局部到整体的解题思路

当只有一条木板时,设g[i][j][k]表示第i个木板前j个格子刷k次的最大值
则g[i][j][k]=max{g[i][t][k-1]+w(t+1,j)}(t<j)
w(x,y)表示第x个到第y个格子的最多同色格子数(前缀和)
有多条木板时,设f[i][j]表示前i个木板刷j次的最大答案
f[i][j]=max{f[i-1][k]+g[i][m][j-k]}(k<=j)

这里引用zhhx的一句话:其实像这种一般的dp,就是把影响答案的信息用多维状态来表示,什么

必要什么就放在状态里。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,t;
int a[55][55];
int s1[55][55]={},s2[55][55]={};//s1:0 s2:1
int f[55][2550];
int g[55][55][55];
int wid(int i,int x,int y)
{
    return max(s1[i][y]-s1[i][x-1],s2[i][y]-s2[i][x-1]);
}
int tim;
int main()
{
    ios::sync_with_stdio(0);
    cin>>n>>m>>tim;
    for(int i=1;i<=n;i++)
    {
        string str;cin>>str;
        for(int j=1;j<=str.size();j++)
        {
            if(str[j-1]=='0')a[i][j]=0;
            else a[i][j]=1;
            if(a[i][j]==0)s1[i][j]=s1[i][j-1]+1,s2[i][j]=s2[i][j-1];else s1[i][j]=s1[i][j-1],s2[i][j]=s2[i][j-1]+1;
        }
    }
    for(int i=1;i<=n;i++)//第i个木板
    for(int j=1;j<=m;j++)//前j个格子
    for(int k=1;k<=j;k++)//刷了k次
    for(int t=0;t<j;t++)//前t个格子
    {
        g[i][j][k]=max(g[i][j][k],g[i][t][k-1]+wid(i,t+1,j));
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=tim;j++)
    for(int k=0;k<=j;k++)
    {
        int cnt=0;
        if(j-k>=m)cnt=m;else cnt=g[i][m][j-k];
        f[i][j]=max(f[i-1][k]+cnt,f[i][j]);
    }
    cout<<f[n][tim]<<endl;
    return 0;
}

posted @ 2019-07-24 15:02  Akaina  阅读(149)  评论(0编辑  收藏  举报