Luogu P4158 [SCOI2009]粉刷匠(dp+背包)

P4158 [SCOI2009]粉刷匠

题意

题目描述

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

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

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

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

输入输出格式

输入格式:

第一行包含三个整数,\(N\ M\ T\)

接下来有\(N\)行,每行一个长度为\(M\)的字符串,\(0\)表示红色,\(1\)表示蓝色。

输出格式:

包含一个整数,最多能正确粉刷的格子数。

输入输出样例

输入样例#1:

3 6 3
111111
000000
001100

输出样例#1:

16

说明

\(30\%\)的数据,满足\(1\leq N,M\leq 10,0\leq T\leq 100\)

\(100\%\)的数据,满足\(1\leq N,M\leq 50,0\leq T\leq 2500\)

思路

如果我们能计算出第\(i\)行涂了\(j\)次的最少错误颜色数,这题不就可以直接背包了吗?

求出这个东西,其实也是要\(dp\)的。设\(f[i][j][k][w]\)为第\(i\)行第\(j\)列, 涂了\(k\)次, 最后一块涂的颜色为\(w\)时这一行的最少错误颜色数。\(w=0\)表示没有涂色,\(w=1\)表示涂了红色,\(w=2\)表示涂了蓝色。那么就有:

for(int i=1;i<=n;i++)
{
    f[i][1][0][0]=f[i][1][1][1]=f[i][1][1][2]=1;
    if(ch[i][1]=='0') f[i][1][1][1]=0;
    else f[i][1][1][2]=0;
    for(int j=2;j<=m;j++)
        for(int k=0;k<=j;k++)
        {
            f[i][j][k][0]=min(f[i][j-1][k][0],min(f[i][j-1][k][1],f[i][j-1][k][2]))+1;
            if(ch[i][j]=='0') f[i][j][k][1]=f[i][j-1][k][1],f[i][j][k][2]=f[i][j-1][k][2]+1;
            else f[i][j][k][2]=f[i][j-1][k][2],f[i][j][k][1]=f[i][j-1][k][1]+1;
            if(k>0)
            {
                if(ch[i][j]=='0')
                {
                    f[i][j][k][1]=min(f[i][j][k][1],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2]));
                    f[i][j][k][2]=min(f[i][j][k][2],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2])+1);
                }
                else
                {
                    f[i][j][k][2]=min(f[i][j][k][2],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2]));
                    f[i][j][k][1]=min(f[i][j][k][1],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2])+1);
                }
            }
        }

然后背包就好啦。背包的代码见下面。

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,m,t,f[55][55][55][3],g[55][55],dp[55][2505];
///0:NULL, 1:RED(0), 2:BLUE(1)
///f[i][j][k][w]: 第i行第j列, 涂了k次, 最后一块为w
char ch[55][55];
int main()
{
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>ch[i][j];
    memset(f,0x3f,sizeof f);
    for(int i=1;i<=n;i++)
    {
        f[i][1][0][0]=f[i][1][1][1]=f[i][1][1][2]=1;
        if(ch[i][1]=='0') f[i][1][1][1]=0;
        else f[i][1][1][2]=0;
        for(int j=2;j<=m;j++)
            for(int k=0;k<=j;k++)
            {
                f[i][j][k][0]=min(f[i][j-1][k][0],min(f[i][j-1][k][1],f[i][j-1][k][2]))+1;
                if(ch[i][j]=='0') f[i][j][k][1]=f[i][j-1][k][1],f[i][j][k][2]=f[i][j-1][k][2]+1;
                else f[i][j][k][2]=f[i][j-1][k][2],f[i][j][k][1]=f[i][j-1][k][1]+1;
                if(k>0)
                {
                    if(ch[i][j]=='0')
                    {
                        f[i][j][k][1]=min(f[i][j][k][1],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2]));
                        f[i][j][k][2]=min(f[i][j][k][2],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2])+1);
                    }
                    else
                    {
                        f[i][j][k][2]=min(f[i][j][k][2],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2]));
                        f[i][j][k][1]=min(f[i][j][k][1],min(min(f[i][j-1][k-1][0],f[i][j-1][k-1][1]),f[i][j-1][k-1][2])+1);
                    }
                }
            }
    }
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            g[i][j]=min(f[i][m][j][0],min(f[i][m][j][1],f[i][m][j][2]));
    memset(dp,0x3f,sizeof dp);
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=t;j>=0;j--)
            for(int k=0;k<=min(j,m);k++)
                dp[i][j]=min(dp[i][j],dp[i-1][j-k]+g[i][k]);
    printf("%d",n*m-dp[n][t]);
    return 0;
}
posted @ 2018-11-04 17:29  UranusITS  阅读(149)  评论(0编辑  收藏  举报