1. 程式人生 > >BZOJ1296: [SCOI2009]粉刷匠(洛谷P4158)

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

DP

我連揹包都不會了

做兩遍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; }