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 ...
随机推荐
- NOIp2018集训test-9-6(pm)
T1T2是洛谷原题.Orz辉神290,被辉神吊起来打. 题 1 包裹快递 二分答案.这题似乎卡精度,不开long double二分500次都过不去. //Achen #include<algor ...
- NX二次开发-将信息窗口中的文本保存到文本文件中UF_UI_save_listing_window
#include <uf.h> #include <uf_ui.h> UF_initialize(); //打开信息窗口 UF_UI_open_listing_window() ...
- (转)HashMap和HashSet的区别
HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...
- Spring源码由浅入深系列六 CreateBean过程
- TCP/IP点滴
1 子网的划分 2 子网的表述 ipv4 IPv4中规定IP地址长度为32,最大地址个数为2^32,点分十进制表示方法:122.70.156.25. ipv6 地址的长度为128,即最大地址个数为2^ ...
- Day 13 : 函数递归,
从前有有座山,山里有座庙,庙里有个老和尚给小和尚们讲故事,讲的什么呀,讲的是,从前有有座山,山里有座庙,庙里有个老和尚给小和尚们讲故事,讲的什么呀?讲的是?...... 递归:1.一个函数再内部调用了 ...
- POJ 3667 线段树区间合并裸题
题意:给一个n和m,表示n个房间,m次操作,操作类型有2种,一种把求连续未租出的房间数有d个的最小的最左边的房间号,另一个操作时把从x到x+d-1的房间号收回. 建立线段树,值为1表示未租出,0为租出 ...
- JAVA时间工具类用法
1.获得N天前的TIMESTAMP Calendar cl = Calendar.getInstance(); cl.add(Calendar.DAY_OF_YEAR, -7); Date date ...
- 机器突然宕机导致hdfs启动一直超时的行为
今天手里其中一个集群几个机器突然宕机,启动hdfs一直超时. clouder-scm-agent主要报了这个错RROR: Unexpected error 'getpwuid(): uid not f ...
- 2019-7-3-Roslyn-在项目文件使用条件判断
title author date CreateTime categories Roslyn 在项目文件使用条件判断 lindexi 2019-7-3 17:7:32 +0800 2018-8-3 2 ...