1296: [SCOI2009]粉刷匠
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2935 Solved: 1700
[Submit][Status][Discuss]
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][j][k]表示第i行的前j个格子涂了k次颜色时,最多能正确涂的格子数
Sum[i][j]表示第i行到j的前缀和(0/1)
那么
dp[i][j][k]=max(dp[i][l][k-1]+Sum[i][j]-Sum[i][l],dp[i][j][k]) 将第i行的[l+1,j]涂1这种颜色
dp[i][j][k]=max(dp[i][l][k-1]+(j-l)-(Sum[i][j]-Sum[i][l]),dp[i][j][k]) 将第i行的[l+1,j]涂0这种颜色
最后再做个背包,设dpB[i][j]表示前i行每行选一个涂颜色的次数,一共涂了j次颜色的最多能正确涂的格子数
那么 dpB[i][j]=max(dpB[i][j],dpB[i-1][j-k]+dp[i][M][k])
Code
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 #include <vector> 6 using namespace std; 7 8 int Col[51][51]; 9 int dp[51][51][51]; 10 int dpB[51][2501]; 11 int Sum[51][51]; 12 int N,M,T; 13 14 int main(){ 15 cin>>N>>M>>T; 16 for(register int i=1;i<=N;++i) 17 for(register int j=1;j<=M;++j){ 18 char c;cin>>c; 19 if(c=='0') Col[i][j]=0; 20 else Col[i][j]=1; 21 Sum[i][j]=Sum[i][j-1]+Col[i][j]; 22 } 23 for(register int i=1;i<=N;++i) 24 for(register int j=1;j<=M;++j) 25 for(register int k=1;k<=j;++k) 26 for(register int l=k-1;l<j;++l){ 27 dp[i][j][k]=max(dp[i][l][k-1]+Sum[i][j]-Sum[i][l],dp[i][j][k]); 28 dp[i][j][k]=max(dp[i][l][k-1]+(j-l)-(Sum[i][j]-Sum[i][l]),dp[i][j][k]); 29 } 30 for(register int i=1;i<=N;++i) 31 for(register int j=T;j>=1;--j) 32 for(register int k=1;k<=j;++k) 33 dpB[i][j]=max(dpB[i][j],dpB[i-1][j-k]+dp[i][M][k]); 34 int Ans=0; 35 for(register int i=1;i<=T;++i) 36 Ans=max(Ans,dpB[N][i]); 37 cout<<Ans<<endl; 38 39 return 0; 40 }