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. NX二次开发-创建直线UF_CURVE_create_line与NXOpen->CreateLine

    NX11+VS2013 #include <uf.h> #include <uf_curve.h> #include <NXOpen/CurveCollection.hx ...

  2. NX二次开发-UFUN移动工程图视图UF_DRAW_move_view

    #include <uf.h> #include <uf_draw.h> #include <uf_drf.h> #include <uf_obj.h> ...

  3. NX二次开发-UFUN获取边的端点UF_MODL_ask_edge_verts

    NX9+VS2012 #include <uf.h> #include <uf_modl.h> #include <uf_ui.h> #include <uf ...

  4. LeetCode 620. Not Boring Movies (有趣的电影)

    题目标签: 题目给了我们一个 cinema 表格, 让我们找出 不无聊的电影,并且id 是奇数的,降序排列. 比较直接简单的,具体看code. Java Solution: Runtime:  149 ...

  5. 【Web】浅析JQuery的apply(), call(), bind()方法

    原文地址:https://blog.csdn.net/whuzxq/article/details/64166253 由于在理解this的用法的时候多次出现了这几个方法,个人对这几个方法理解的不是很透 ...

  6. Codeforces 1168A Increasing by Modulo

    题目链接:http://codeforces.com/problemset/problem/1168/A 题意:给一个数组,数组中元素范围为0~n,每次你可以选择若干元素进行(ai+1)%m的操作,问 ...

  7. mybatis 3 批量插入返回主键 Parameter 'id' not found

    @Insert("<script>INSERT INTO scp_activity_gift (activity_id,type,gift_id,status,limit_num ...

  8. 根据单个或多个字段对list对象去重

    pojo  省略 在list 对象中,根据某一字段进行去重,重写Comparator /** * 去重 * * @param orderList * @return * @author ziggo * ...

  9. 4.1_springboot2.2任务之异步、定时、邮件任务

    1.异步任务 ​ 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spri ...

  10. css3的选择器

    先来做一下准备工作 页面的效果: 看到上面的框框了吗?我们就是通过给这些框框添加背景色的方式,来让大家,了解css3的选择器的效果,下面正式开始: 关联选择器 E1~E2 选择 E1 后面的兄弟 E2 ...