bzoj1296: [SCOI2009]粉刷匠
dp.
用到俩次dp,用1和0代表俩种颜色,首先对于每块木板我们进行一次dp,g[i][j]代表前j个格子刷i次最多能涂到几个格子。
则 g[i][j]=max(g[i-1][k],max(cnt[j]-cnt[k],j-k-cnt[j]+cnt[k])。 k < j,cnt[j]代表前j个格子1的数量。
f[r][j]=g[r][j][m],g数组为循环利用,r代表是第i块木板。
这样对于整体来说,又变成了一个背包问题。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 100 + 10; int n,m,t; int a[maxn],cnt[maxn]; int g[maxn][maxn],f[maxn][maxn],F[maxn][maxn*maxn]; int main() { scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++) { memset(g,0,sizeof(g)); memset(cnt,0,sizeof(cnt)); for(int j=1;j<=m;j++) { scanf("%1d",&a[j]); if(a[j]) cnt[j]=cnt[j-1]+1; else cnt[j]=cnt[j-1]; } for(int i=1;i<=m;i++) for(int j=i;j<=m;j++) { for(int k=i-1;k<j;k++) g[i][j]=max(g[i][j],g[i-1][k]+max(cnt[j]-cnt[k],j-k-cnt[j]+cnt[k])); } for(int j=1;j<=m;j++) f[i][j]=g[j][m]; } memset(F,0,sizeof(F)); for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=j;k<=t;k++) F[i][k]=max(F[i][k],F[i-1][k-j]+f[i][j]); printf("%d\n",F[n][t]); return 0; }