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;
}
posted @ 2016-06-17 10:57  invoid  阅读(232)  评论(0编辑  收藏  举报