BZOJ1296: [SCOI2009]粉刷匠(洛谷P4158)

292 篇文章 1 订阅
281 篇文章 1 订阅

DP

BZOJ题目传送门
洛谷题目传送门

我连背包都不会了

做两遍DP,第一遍求出每一行刷 k k k次分别最多能刷对多少个格子。第二遍就把第一遍的当作分组背包来选物品就好了。

f [ i ] [ j ] f[i][j] f[i][j]表示当前这行做到第 i i i列,刷了 j j j次的最多格子数。那么有 f [ i ] [ j ] = m a x { f [ k ] [ j − 1 ] + m a x { s 0 i − s 0 k , s 1 i − s 1 k } } f[i][j]=max\{f[k][j-1]+max\{s0_i-s0_k,s1_i-s1_k\}\} f[i][j]=max{f[k][j1]+max{s0is0k,s1is1k}}。其中 s 0 , s 1 s0,s1 s0,s1分别为 0 0 0 1 1 1的前缀和。

分组背包就不用说了吧。。。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 55
using namespace std;
int n,m,t,ans,s0[N],s1[N],f[N][N],g[N][N*N];
char s[N];
int main(){
	scanf("%d%d%d",&n,&m,&t);
	for (int i=1;i<=n;i++){
		scanf("%s",s+1);
		for (int j=1;j<=m;j++){
			s0[j]=s0[j-1],s1[j]=s1[j-1];
			s[j]=='0'?s0[j]++:s1[j]++;
			for (int k=0;k<=m;k++) f[j][k]=0;
		}
		for (int j=1;j<=m;j++)
		for (int p=1;p<=j;p++)
		for (int k=0;k<j;k++)
			f[j][p]=max(f[j][p],f[k][p-1]+max(s0[j]-s0[k],s1[j]-s1[k]));
		for (int j=1;j<=t;j++)
		for (int k=0,p=min(m,j);k<=p;k++)
			g[i][j]=max(g[i][j],g[i-1][j-k]+f[m][k]);
	}
	for (int i=1;i<=t;i++) ans=max(ans,g[n][i]);
	return printf("%d",ans),0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值