zoukankan      html  css  js  c++  java
  • 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\%)的数据,满足(1leq N,Mleq 10,0leq Tleq 100)

    (100\%)的数据,满足(1leq N,Mleq 50,0leq Tleq 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;
    }
    
  • 相关阅读:
    xml实现AOP
    AOP
    python 大小写转换方法(全)
    vs2013 快捷键
    构造方法后面带:this()
    资源的使用----实例分析
    把列表变成用指定字符连接的字符串
    python 列表、元组操作
    工作踩坑记录:JavaScript跳转被缓存
    《Effective Java》读书笔记
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9904843.html
Copyright © 2011-2022 走看看