BZOJ1296 [SCOI2009]粉刷匠 【dp】

題目

windy有 N 條木板需要被粉刷。 每條木板被分爲 M 個格子。 每個格子要被刷成紅色或藍色。 windy每次粉刷,只能選擇一條木板上一段連續的格子,然後塗上一種顏色。 每個格子最多隻能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正確粉刷多少格子? 一個格子如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。

輸入格式

輸入文件paint.in第一行包含三個整數,N M T。 接下來有N行,每行一個長度爲M的字符串,’0’表示紅色,’1’表示藍色。

輸出格式

輸出文件paint.out包含一個整數,最多能正確粉刷的格子數。

輸入樣例

3 6 3

111111

000000

001100

輸出樣例

16

提示

30%的數據,滿足 1 <= N,M <= 10 ; 0 <= T <= 100 。 100%的數據,滿足 1 <= N,M <= 50 ; 0 <= T <= 2500 。

題解

將每一行做一次O(M3) 動歸,求出每行刷k次下做多的收益
f[i][j] 表示當前行前i個刷j次的最大收益
f[i][j]=max(f[k][j1]+max(sum1(k,j),sum0(k,j)))
得出了每行刷1、2、3……K次的收益,總共可以刷T次,就可以做一個分組揹包

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
using namespace std;
const int maxn = 60,maxm = 2505,INF = 1000000000;
int f[maxn][maxm],g[maxn][maxn],N,M,T,sum[maxn];
char s[maxn];
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++) sum[j] = sum[j - 1] + (s[j] == '1');
        for (int k = 1; k <= M; k++)
            for (int j = 1; j <= M; j++){
                g[j][k] = 0;
                for (int l = 0; l < j; l++)
                    g[j][k] = max(g[j][k],g[l][k - 1] + max(sum[j] - sum[l],j - l - (sum[j] - sum[l])));
            }
        for (int j = 1; j <= T; j++)
            for (int k = 1,t = min(j,M); k <= t; k++)
                f[i][j] = max(f[i][j],f[i - 1][j - k] + g[M][k]);
    }
    int ans = 0;
    REP(i,T) ans = max(ans,f[N][i]);
    printf("%d",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章