1296: [SCOI2009]粉刷匠
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2339 Solved: 1348
[ Submit][ Status][ Discuss]
Description
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。 windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
Input
输入文件paint.in第一行包含三个整数,N M T。 接下来有N行,每行一个长度为M的字符串,'0'表示红色,'1'表示蓝色。
Output
输出文件paint.out包含一个整数,最多能正确粉刷的格子数。
Sample Input
3 6 3
111111
000000
001100
Sample Output
16
这题就是
两道很简单的DP拼在一起
①第一步:对于每个木板,dp[i][j]表示前j个格子染i次最多能染多少个格子
②第二步:可以由第一步直接得到:bet[i][j]表示第i个木板染j次最多能染多少个格子
③第三步:背包DP,ba[i][j]表示染前i个木板已经染了j次最多能染多少个格子
答案就是max(ba[n][k] k∈(1, T))
复杂度:O(nmT)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[55][55], sum[55][55], dp[2555][55], bet[55][2555], ba[55][2555];
int main(void)
{
int n, m, T, i, j, k, p, ans;
scanf("%d%d%d", &n, &m, &T);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%1d", &a[i][j]);
sum[i][j] = sum[i][j-1]+a[i][j];
}
}
for(i=1;i<=n;i++)
{
memset(dp, 0, sizeof(dp));
for(j=1;j<=min(T,m);j++)
{
for(k=1;k<=m;k++)
{
for(p=0;p<=k-1;p++)
dp[j][k] = max(dp[j][k], dp[j-1][p]+max(sum[i][k]-sum[i][p], k-p-(sum[i][k]-sum[i][p])));
}
bet[i][j] = dp[j][m];
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=T;j++)
{
for(k=1;k<=min(j,m);k++)
ba[i][j] = max(ba[i][j], ba[i-1][j-k]+bet[i][k]);
}
}
ans = 0;
for(i=1;i<=T;i++)
ans = max(ans, ba[n][i]);
printf("%d\n", ans);
return 0;
}