BZOJ系列1296《[SCOI2009]粉刷匠》题解

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 。


分析:可以用动态规划来解决。

dp[i][j]表示该行前i个涂j次的最优解。

最后再对于每行做分组背包。


代码如下:

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int N,M,T,sum[60],ans;
int t[60][60],f[60][2510];
char s[60];
void init()
{
	scanf("%d%d%d",&N,&M,&T);
}
void work()
{
	for(int i=1;i<=N;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=M;j++) sum[j]=sum[j-1]+(s[j]=='1');
		for(int j=1;j<=M;j++)
			for(int x=1;x<=M;x++)
			{
				t[x][j]=0;
				for(int y=0;y<x;y++)
				{
					int tmp=sum[x]-sum[y];
					t[x][j]=max(t[x][j],t[y][j-1]+max(tmp,x-y-tmp));
				}
			}
		for(int j=1;j<=T;j++)
		{
			int tmp=min(M,j);
			for(int k=1;k<=tmp;k++)
				f[i][j]=max(f[i][j],f[i-1][j-k]+t[M][k]);
		}
	}
	for(int i=1;i<=T;i++)
		ans=max(f[N][i],ans);
	printf("%d\n",ans);
}
int main()
{
	init();
	work();
	return 0;
}



猜你喜欢

转载自blog.csdn.net/Dante__Alighieri/article/details/43968459