BZOJ1296 [SCOI2009] 粉刷匠 【dp】
BZOJ1296 [SCOI2009] 粉刷匠
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
111111
000000
001100
Sample Output
16
HINT
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。 100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。
题解:
两遍 dp,主循环 i=1~n,首先第一次先把第 i 行的前 j 个格涂 k 次的 dp 求出来,然后第二次再把前 i 行涂 j 次的 dp 求出来,最后 max(dp[n][i]) 就是最终答案。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,t,ans; 4 int sum[55]; 5 int f[55][55],dp[55][2505]; 6 char s[60]; 7 int main() 8 { 9 scanf("%d%d%d",&n,&m,&t); 10 for (int i=1; i<=n; i++) 11 { 12 scanf("%s",s+1); 13 for (int j=1; j<=m; j++) 14 sum[j]=sum[j-1]+(s[j]=='1'); 15 for (int j=1; j<=m; j++) 16 for (int x=1; x<=m; x++) 17 { 18 f[x][j]=0; 19 for (int y=0; y<x; y++) 20 { 21 int tmp=sum[x]-sum[y]; 22 f[x][j]=max(f[x][j],f[y][j-1]+max(tmp,x-y-tmp)); 23 } 24 } 25 for (int j=1; j<=t; j++) 26 { 27 int tmp=min(m,j); 28 for (int k=1; k<=tmp; k++) 29 dp[i][j]=max(dp[i][j],dp[i-1][j-k]+f[m][k]); 30 } 31 } 32 for (int i=1; i<=t; i++) 33 ans=max(dp[n][i],ans); 34 cout<<ans<<endl; 35 return 0; 36 }
加油加油加油!!! fighting fighting fighting !!!