Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 2174 Solved: 1253
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
HINT
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。 100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。
Source
自己代码能力太差啦,写了五十分钟才把这道题写出来,真是弱鸡
dalao讲解
首先这道题我们先对于每一排进行一个dp,dp出在i这一排刷j次的最大收益,显然的一个三维dp
然后我们就dp前i个物品里刷j次,其中第i个物品刷k次的最大收益,用一维数组滚动优化空间,答案就是ans[T],也就是前n个物品一共刷T次
发现此类代码虽然简单,但是很可能一个小细节会挂得很惨,考试的时候也不敢不对拍,还得练练写暴力
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 60;
int N,M,T,a[MAXN][MAXN],dp[MAXN][MAXN],f[MAXN][MAXN],ans[3000],sum[MAXN];
//dp[i][j] 前i格,刷j次最多刷对几个
int main()
{
scanf( "%d%d%d", &N, &M, &T );
for( register int i = 1; i <= N; i++ )
for( register int j = 1; j <= M ; j++ ) scanf("%1d",&a[i][j]);
for( register int r = 1; r <= N; r++ ) {
sum[0] = 0;
memset( dp, 0, sizeof(dp) );
//dp[i][j] 为刷前i个刷j次最多收益
for( register int i = 1; i <= M; i++ ) sum[i] = sum[ i - 1 ] + a[r][i];
for( register int i = 1; i <= M; i++ )
for( register int j = 1; j <= i; j++ )
for( register int k = 0; k < i; k++ )
dp[i][j] = max( dp[i][j], dp[k][ j - 1 ] + max( sum[i] - sum[k], i - k - sum[i] + sum[k] ) );
for( register int i = 1; i <= M; i++ ) f[r][i] = dp[M][i];
}
for( register int i = 1; i <= N; i++ )
for( register int j = T; j >= 1; j-- )
for( register int k = 1; k <= M; k++ )
if( k <= j ) ans[j] = max( ans[j], ans[ j - k ] + f[i][k] );
printf("%d\n",ans[T]);
return 0;
}