首页 > 代码库 > BZOJ 1296 SCOI2009 粉刷匠 动态规划

BZOJ 1296 SCOI2009 粉刷匠 动态规划

题目大意:给定n*m的木板,每个点需要刷成1和0两种颜色之一,每次只能刷一行中连续的一段,一个点只能刷一次,求T刷子最多能刷对多少个点

首先对每行拆开处理 令f[i][j]为用i刷子刷前j个格子最多刷对多少个点 动规处理出这一行刷i刷子最多能刷对多少个点 然后分组背包即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 60
using namespace std;
int n,m,T,f[M][M];
//f[i][j]表示用i刷子刷前j个格子能刷出的最多格子
//f[i][j]=max{ f[i-1][k]+max(cnt[0],cnt[1]) }
//(i-1<=k<=j-1)
char s[M];
int a[M][M];
//a[i][j]表示第i行用j刷子能刷出的最大价值
void DP(int pos)
{
	int i,j,k;
	memset(f,0xef,sizeof f);
	f[0][0]=0;
	for(i=1;i<=m;i++)
	{
		for(j=i;j<=m;j++)
		{
			int cnt[2]={0};
			for(k=j-1;k>=i-1;k--)
			{
				cnt[s[k+1]-'0']++;
				f[i][j]=max(f[i][j],f[i-1][k]+max(cnt[0],cnt[1]));
			}
		}
	}
	for(i=1;i<=m;i++)
		a[pos][i]=f[i][m];
}
int Packet_Backpack()
{
	int i,j,k;
	static int g[M][M*M];
	memset(g,0xef,sizeof g);
	g[0][0]=0;
	for(i=1;i<=n;i++)
		for(j=0;j<=m;j++)
			for(k=T;k>=j;k--)
				g[i][k]=max(g[i][k],g[i-1][k-j]+a[i][j]);
	return g[n][T];
}
int main()
{
	int i;
	cin>>n>>m>>T;
	for(i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		DP(i);
	}
	cout<<Packet_Backpack()<<endl;
}


BZOJ 1296 SCOI2009 粉刷匠 动态规划