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

DP

BZOJ題目傳送門
洛谷題目傳送門

我連揹包都不會了

做兩遍DP,第一遍求出每一行刷kk次分別最多能刷對多少個格子。第二遍就把第一遍的當作分組揹包來選物品就好了。

f[i][j]f[i][j]表示當前這行做到第ii列,刷了jj次的最多格子數。那麼有f[i][j]=max{f[k][j1]+max{s0is0k,s1is1k}}f[i][j]=max\{f[k][j-1]+max\{s0_i-s0_k,s1_i-s1_k\}\}。其中s0,s1s0,s1分別爲0011的前綴和。

分組揹包就不用說了吧。。。

代碼:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章