Luogu P4158 [SCOI2009]粉刷匠(dp+背包)
题意
题目描述
\(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+背包)的更多相关文章
- [Bzoj1296][Scoi2009] 粉刷匠 [DP + 分组背包]
1296: [SCOI2009]粉刷匠 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2184 Solved: 1259[Submit][Statu ...
- BZOJ 1296: [SCOI2009]粉刷匠( dp )
dp[ i ][ j ] = max( dp[ i - 1 ][ k ] + w[ i ][ j - k ] ) ( 0 <= k <= j ) 表示前 i 行用了 j 次粉刷的机会能正 ...
- 【题解】洛谷P4158 [SCOI2009] 粉刷匠(DP)
次元传送门:洛谷P4158 思路 f[i][j][k][0/1]表示在坐标为(i,j)的格子 已经涂了k次 (0是此格子涂错 1是此格子涂对)涂对的格子数 显然的是 每次换行都要增加一次次数 那么当j ...
- BZOJ1296: [SCOI2009]粉刷匠 DP
Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个 ...
- P4158[SCOI2009]粉刷匠
题目描述 windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个格子最多只能被 ...
- P4158 [SCOI2009]粉刷匠(洛谷)
今天A了个紫(我膨胀了),他看起来像个贪心一样,老师说我写的是dp(dp理解不深的缘故QWQ) 直接放题目描述(我旁边有个家伙让我放链接,我还是说明出处吧(万一出处没有了)我讲的大多数题目都是出自洛谷 ...
- 洛谷P4158 [SCOI2009]粉刷匠
传送门 设$dp[i][j][k][0/1]$表示在涂点$(i,j)$,涂了$k$次,当前点的颜色是否对,最多能刷对多少个格子 首先换行的时候肯定得多刷一次 然后是如果和前一个格子颜色相同,那么当前点 ...
- 洛谷 P4158 [SCOI2009]粉刷匠 题解
每日一题 day59 打卡 Analysis 很容易看出是一个dp, dp[i][j[k][0/1]来表示到了(i,j)时,刷了k次,0表示这个没刷,1表示刷了. 于是有转移: 1.换行时一定要重新刷 ...
- [luogu4158 SCOI2009] 粉刷匠(dp)
传送门 Solution 把状态都记上暴力转移即可 Code //By Menteur_Hxy #include <queue> #include <cmath> #inclu ...
随机推荐
- BZOJ 3779: 重组病毒(线段树+lct+树剖)
题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...
- Python 爬虫-爬取京东手机页面的图片
具体代码如下: __author__ = 'Fred Zhao' import requests from bs4 import BeautifulSoup import os from urllib ...
- HDFS API 操作实例(一) HDFS读写操作
1. 读取HDFS文件 1.1 字符读取HDFS上的文件 Configuration conf = new Configuration(); Path path = new Path(pathstr) ...
- NodeJS学习笔记之Connect中间件应用实例
一,开篇分析 大家好哦,大熊君又来了,昨天因为有点个人的事没有写博客,今天又出来了一篇,这篇主要是写一个记事本的小应用,前面的文章, 我也介绍过“Connect”中间件的使用以及“Mongodb”的用 ...
- canvas前端压缩图片和视频首屏缩略图并上传到服务器
图片: var img = document.createElement('img') img.src = window.URL.createObjectURL(fileObj.file) // 加载 ...
- Spring Cloud Feign设计原理
什么是Feign? Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直 ...
- Xpath-Assertion断言
- MySQL安装配置及测试
1. 安装包下载 点击下载地址:https://dev.mysql.com/downloads/installer/打开页面,滑到较底端,按如下选择下载: 会弹出一个注册登录页面,可以不用管,直接点击 ...
- iOS开发系列-修改项目工程名
当前有项目工程名为iOS,需要修改工程名为IFLY.在修改前注意备份项目 修改项目名 出现弹框,点击Rename 修改工程目录文件名 注意Tests与UITests不要删除 选中IFLY.xcodep ...
- PHP算法之整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123输出: 321 示例 2: 输入: -123输出: -321示例 3: 输入: 120输出: 21注 ...