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. BZOJ 3779: 重组病毒(线段树+lct+树剖)

    题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...

  2. Python 爬虫-爬取京东手机页面的图片

    具体代码如下: __author__ = 'Fred Zhao' import requests from bs4 import BeautifulSoup import os from urllib ...

  3. HDFS API 操作实例(一) HDFS读写操作

    1. 读取HDFS文件 1.1 字符读取HDFS上的文件 Configuration conf = new Configuration(); Path path = new Path(pathstr) ...

  4. NodeJS学习笔记之Connect中间件应用实例

    一,开篇分析 大家好哦,大熊君又来了,昨天因为有点个人的事没有写博客,今天又出来了一篇,这篇主要是写一个记事本的小应用,前面的文章, 我也介绍过“Connect”中间件的使用以及“Mongodb”的用 ...

  5. canvas前端压缩图片和视频首屏缩略图并上传到服务器

    图片: var img = document.createElement('img') img.src = window.URL.createObjectURL(fileObj.file) // 加载 ...

  6. Spring Cloud Feign设计原理

    什么是Feign? Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直 ...

  7. Xpath-Assertion断言

  8. MySQL安装配置及测试

    1. 安装包下载 点击下载地址:https://dev.mysql.com/downloads/installer/打开页面,滑到较底端,按如下选择下载: 会弹出一个注册登录页面,可以不用管,直接点击 ...

  9. iOS开发系列-修改项目工程名

    当前有项目工程名为iOS,需要修改工程名为IFLY.在修改前注意备份项目 修改项目名 出现弹框,点击Rename 修改工程目录文件名 注意Tests与UITests不要删除 选中IFLY.xcodep ...

  10. PHP算法之整数反转

    给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123输出: 321 示例 2: 输入: -123输出: -321示例 3: 输入: 120输出: 21注 ...