[Bzoj 1296][Scoi2009] 粉刷匠 [DP + 分組背包]
阿新 • • 發佈:2017-10-09
des ++ red 處理 bsp 答案 背包 size arp Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2181 Solved: 1258 [Submit][Status][Discuss]
輸入文件paint.in第一行包含三個整數,N M T。 接下來有N行,每行一個長度為M的字符串,‘0‘表示紅色,‘1‘表示藍色。
貼上AC代碼:
1296: [SCOI2009]粉刷匠
Description
windy有 N 條木板需要被粉刷。 每條木板被分為 M 個格子。 每個格子要被刷成紅色或藍色。 windy每次粉刷,只能選擇一條木板上一段連續的格子,然後塗上一種顏色。 每個格子最多只能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正確粉刷多少格子? 一個格子如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。Input
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 。分析:
對於每一塊版子粉刷時是互不相幹的,所以每一塊是單獨求的。 先n^4處理出每一塊版子的dp數組,dp[q][i][x]表示第q塊版子,前x個位置粉刷i次的最大值。 因為每一塊版子單獨處理,可以省掉一維變成dp[i][x] 轉移方程為: dp[i][x] = max(dp[i][x],dp[i - 1][y] + max(blue[q][x] - blue[q][y],red[q][x] - red[q][y])); 然後做分組背包 處理f[i][j],表示前i塊版子,粉刷j次的最大值 轉移方程為: f[q][i] = max(f[q][i],f[q - 1][i - j] + dp[j][m]); 求出f[n][i]中最大值即為答案; 貼上AC代碼:
# include <iostream> # include <cstdio> # include <cstring> using namespace std; char str[52][52]; int dp[52][52]; int blue[52][52],red[52][52]; int f[52][2502]; int n,m,t; int main(){ scanf("%d %d %d",&n,&m,&t); for(int i = 1;i <= n;i++){ scanf("%s",&str[i][1]); } for(int i = 1;i <= n;i++){ for(int j = 1;j <= m;j++){ blue[i][j] = blue[i][j - 1]; red[i][j] = red[i][j - 1]; if(str[i][j] == ‘0‘)blue[i][j]++; else red[i][j]++; } } for(int q = 1; q <= n;q++){ memset(dp,0,sizeof dp); for(int i = 1;i <= min(t,m);i++){ for(int x = 1;x <= m;x++){ for(int y = 0;y < x;y++){ dp[i][x] = max(dp[i][x],dp[i - 1][y] + max(blue[q][x] - blue[q][y],red[q][x] - red[q][y])); } } } for(int i = 1;i <= t;i++){ for(int j = 1;j <= min(i,m);j++){ f[q][i] = max(f[q][i],f[q - 1][i - j] + dp[j][m]); } } } int ans = 0; for(int i = 1;i <= t;i++)ans = max(ans,f[n][i]); printf("%d\n",ans); return 0; }
[Bzoj 1296][Scoi2009] 粉刷匠 [DP + 分組背包]