1. 程式人生 > >BZOJ_1296_[SCOI2009]粉刷匠_DP

BZOJ_1296_[SCOI2009]粉刷匠_DP

整數 int scanf pac esc sample 一行 \n algo

BZOJ_1296_[SCOI2009]粉刷匠_DP

Description

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

Input

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

Output

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

Sample Input

3 6 3
111111
000000
001100

Sample Output

16

HINT

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


由於每行之間是獨立的,可以分別對每行DP。

設h[i][j]表示前i個位置塗了j次。

然後放在一起,用每行使用塗的次數來轉移。

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
int h[55][55],g[55][55],f[55][2550],n,m,K,s1[55],s2[55];
char s[55];
int main() {
	scanf("%d%d%d",&n,&m,&K);
	int i,j,k,l;
	for(i=1;i<=n;i++) {
		scanf("%s",s+1);
		for(j=1;j<=m;j++) s1[j]=s1[j-1]+(s[j]==‘1‘),s2[j]=s2[j-1]+(s[j]==‘0‘);
		memset(h,0,sizeof(h));
		for(j=1;j<=m;j++) {
			for(k=1;k<=j;k++) {
				h[j][k]=h[j-1][k];
				for(l=0;l<j;l++) {
					h[j][k]=max(h[j][k],h[l][k-1]+max(s1[j]-s1[l],s2[j]-s2[l]));
				}
			}
		}
		for(j=1;j<=m;j++) g[i][j]=h[m][j];
	}
	int ans=0;
	for(i=1;i<=n;i++) {
		for(j=0;j<=K;j++) {
			for(k=0;k<=j;k++) {
				f[i][j]=max(f[i][j],f[i-1][k]+g[i][j-k]);
			}
			ans=max(ans,f[i][j]);
		}
	}
	printf("%d\n",ans);
}

BZOJ_1296_[SCOI2009]粉刷匠_DP