zoukankan      html  css  js  c++  java
  • [BZOJ1296][SCOI2009]粉刷匠

    题目描述 Description

    windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。 windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

    输入描述 Input Description

    输入文件paint.in第一行包含三个整数,N M T。 接下来有N行,每行一个长度为M的字符串,'0'表示红色,'1'表示蓝色。

    输出描述 Output Description

    输出文件paint.out包含一个整数,最多能正确粉刷的格子数。

    样例输入 Sample Input

    3 6 3
    111000
    110000
    001100

    样例输出 Sample Output

    16

    数据范围及提示 Data Size & Hint

    30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。 100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。

    之前的一些废话:过了一个非常愉快的暑假(去了欧洲,最后还临时在 杭州待了四天,爱奇艺充了一个月的会员,看了19部电影(《金刚狼1》《金刚狼2》《金刚狼3》《X战警1》《X战警2》《X战警3》《X战警第一战》《X战警逆转未来》《X战警天启》《战狼2》《摔跤吧!爸爸》《哈利波特与魔法石》《哈利波特与密室》《哈利波特与阿兹卡班的囚徒》《哈利波特与火焰杯》《哈利波特与凤凰社》《哈利波特与混血王子》《哈利波特与死亡圣器上》)《哈利波特与死亡圣器下》)可谓是浪上天了。所以得到的报应是开学考试继续炸。接下来的生活要步入正轨了!

    题解:逐个分析每一行:设dp(i,j)表示到第i个格一共刷了j次,转移的话需要枚举 之前所有的k(0<=k<i),转移方程:dp(i,j)=max(dp(i,j),dp(i,k)+max(num1(k+1,i),num0(k+1,i))) num0(i,j)表示在(i,j)这些格之间数字0的数量,num1(i,j)类似,所以这个拿可以前缀和优化成O(n^4)。求完之后,我们设v(i,j)表示第i行刷j次的最大收益,转移为v(i,j)=dp(m,j)

    之后问题就转化为了有一个容量为T的背包,有n组物品,每组有min(m,T)个物品可选,只能选一个,其中价值为v[i][j],重量是j。这个就可以进行DP来进行处理了。总复杂度O(n^4)

    代码:

    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef pair<int,int> PII;
    #define X first
    #define Y second
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int maxn=55,maxt=2550;
    int n,m,t,dp[maxn][maxn],pre0[maxn],pre1[maxn],v[maxn][maxn],dp2[maxn][maxt];//v[i][j]表示第i行用j个最大代价 
    char s[maxn];
    int main()
    {
        n=read();m=read();t=read();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            mem(pre0,0);mem(pre1,0);mem(dp,0);
            for(int j=1;j<=m;j++)
            {
                pre0[j]=pre0[j-1]+(s[j]=='0');
                pre1[j]=pre1[j-1]+(s[j]=='1');
            }
            //for(int j=1;j<=m;j++)printf("j:%d pre0:%d pre1:%d
    ",j,pre0[j],pre1[j]);
            for(int j=1;j<=m;j++)
                for(int k=1;k<=min(t,j);k++)
                    for(int l=0;l<j;l++)dp[j][k]=max(dp[j][k],dp[l][k-1]+max(pre0[j]-pre0[l],pre1[j]-pre1[l]));
            for(int j=1;j<=min(m,t);j++)v[i][j]=dp[m][j];
            //for(int j=1;j<=m;j++)for(int k=1;k<=min(t,j);k++)printf(" %d %d %d
    ",j,k,dp[j][k]);
            //for(int j=1;j<=min(m,t);j++)printf("%d: %d
    ",j,v[i][j]);
        }//有n组物品,每组有min(m,t)个物品可选,只能选一个,其中价值为v[i][j],重量是j,dp[i][j] 
        for(int i=1;i<=n;i++)
            for(int j=1;j<=t;j++)
                for(int l=1;l<=min(m,j);l++)
                    dp2[i][j]=max(dp2[i][j],dp2[i-1][j-l]+v[i][l]);
        printf("%d
    ",dp2[n][t]);
        return 0;
    }=
    View Code

    总结:好像没什么话要说

  • 相关阅读:
    DJango简单的后台定义登录验证
    简单聊聊HTTP/TCP/IP协议
    简单的线程说明
    设计模式 -- 常用设计模式
    网络知识 -- 第二部
    c#利用脚本,本地执行linux命令
    Json和类之间的转化
    关于地址映射穿透和套接字复用的说明
    多线程调用中的注意事项
    Task多线程的常规用法
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7459442.html
Copyright © 2011-2022 走看看