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;
}

Luogu P4158 [SCOI2009]粉刷匠(dp+背包)的更多相关文章

  1. [Bzoj1296][Scoi2009] 粉刷匠 [DP + 分组背包]

    1296: [SCOI2009]粉刷匠 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2184  Solved: 1259[Submit][Statu ...

  2. BZOJ 1296: [SCOI2009]粉刷匠( dp )

    dp[ i ][ j ] = max( dp[ i - 1 ][ k ] + w[ i ][ j - k ] )  ( 0 <= k <= j ) 表示前 i 行用了 j 次粉刷的机会能正 ...

  3. 【题解】洛谷P4158 [SCOI2009] 粉刷匠(DP)

    次元传送门:洛谷P4158 思路 f[i][j][k][0/1]表示在坐标为(i,j)的格子 已经涂了k次 (0是此格子涂错 1是此格子涂对)涂对的格子数 显然的是 每次换行都要增加一次次数 那么当j ...

  4. BZOJ1296: [SCOI2009]粉刷匠 DP

    Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个 ...

  5. P4158[SCOI2009]粉刷匠

    题目描述 windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个格子最多只能被 ...

  6. P4158 [SCOI2009]粉刷匠(洛谷)

    今天A了个紫(我膨胀了),他看起来像个贪心一样,老师说我写的是dp(dp理解不深的缘故QWQ) 直接放题目描述(我旁边有个家伙让我放链接,我还是说明出处吧(万一出处没有了)我讲的大多数题目都是出自洛谷 ...

  7. 洛谷P4158 [SCOI2009]粉刷匠

    传送门 设$dp[i][j][k][0/1]$表示在涂点$(i,j)$,涂了$k$次,当前点的颜色是否对,最多能刷对多少个格子 首先换行的时候肯定得多刷一次 然后是如果和前一个格子颜色相同,那么当前点 ...

  8. 洛谷 P4158 [SCOI2009]粉刷匠 题解

    每日一题 day59 打卡 Analysis 很容易看出是一个dp, dp[i][j[k][0/1]来表示到了(i,j)时,刷了k次,0表示这个没刷,1表示刷了. 于是有转移: 1.换行时一定要重新刷 ...

  9. [luogu4158 SCOI2009] 粉刷匠(dp)

    传送门 Solution 把状态都记上暴力转移即可 Code //By Menteur_Hxy #include <queue> #include <cmath> #inclu ...

随机推荐

  1. NX11.0和VS2013 创建NXOpen 开发模版失败解决方案【转载】

    转载自PLM之家论坛 NX11.0和VS2013 创建NXOpen 开发模版失败解决方案 首先我觉得这个可能是西门子疏忽,基本上每个大版本没有补丁前都有类似问题,下面来说说怎么解决吧.注意这里版本,N ...

  2. 牛客多校第八场 B Beauty Values 水题

    题意: 给定一个序列,问你子区间中不同数字数量,在所有子区间中之和为多少. 题解: 统计每个数字在多少个区间中出现即可.对于每个数字,直接枚举左右端点. 注意去重,因此要记录每个数字上一次出现在哪里, ...

  3. Openstack Nova 源码分析 — 使用 VCDriver 创建 VMware Instance

    目录 目录 前言 流程图 nova-compute vCenter 前言 在上一篇Openstack Nova 源码分析 - Create instances (nova-conductor阶段)中, ...

  4. Day15:Python 【模块】及__name__:

    什么是模块: 在Python中,随着这代码的撰写,代码越来越长,所以产生了,模块这个概念,模块是什么?模块就是一个.py文件,在撰写代码时,我们把不同的功能的代码封装到一个.py文件里,用得时候导入 ...

  5. ATC/TC/CF

    10.25 去打 CF,然后被 CF 打了. CF EDU 75 A. Broken Keyboard 精神恍惚,WA 了一发. B. Binary Palindromes 比赛中的憨憨做法,考虑一个 ...

  6. 【HDUOJ】1213 How many tables

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1213 题意:Ignatius邀请了n个朋友来家里,朋友之间如果互相不认识的不想坐一起,所以至少要准备几 ...

  7. web项目中使用的协议

    DNS协议 1.DNS协议的作用是将域名解析为IP,网络上的每个站点的位置是用IP来确定的,访问一个网站首先就要知道它的IP,不过数据组成的IP记起来不方便,所以就使用域名来代替IP,由于IP和域名的 ...

  8. 小白 Linux下安装Elasticsearch5.X

    最近做个项目需要使用到 Elasticsearch5 刚接触liunx 遇到了很多问题记录下 以这篇文章为基础 http://www.cnblogs.com/ShawnYuki/p/6818677.h ...

  9. AndroidStudio WiFi调试插件

    前言 此篇博客也是Android studio插件篇的一部分,后续有时间我会介绍更多AndroidStudio的插件方便开发. Android设备用WiFi调试在以前一般是通过adb连接的,但是这样的 ...

  10. [笔记]Laravel TDD 胡乱记录

    TDD: 测试驱动开发(Test-Driven Development),TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码. -- 载自TDD百度百科 参考 ...