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 。
题解:我觉得这道题的思路还是比较好想的,但是具体落实我自己却不大会,只能。。。
思路是先提前处理好每块木板涂几次时最多能涂几个格子,然后再去讨论前几块木板涂几笔时,所能涂最多的格子,最后前n块木板涂m笔便是答案。
所以这题有两个动归,具体看程序后的注释,会详细解释。
动态转移方程:具体程序看!
#include<iostream> #include<cstdio> #include<string> using namespace std; int n,m,t,sum,f[100][100],f2[100][3000],tot[100],w[100][100]; char a[100][100],ch; int max(int a,int b) { if (a>b) return a; return b; } int main() { cin>>n>>m>>t; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { cin>>ch;//输入 a[i][j]=ch; } for (int k=1;k<=n;k++)//开始一块一块木板处理 { tot[0]=0; for (int i=1;i<=m;i++) if (a[k][i]=='0') tot[i]=tot[i-1]+1; //记录这块木板前i个格子中有几个格子为0(即红色) else tot[i]=tot[i-1]; for (int i=1;i<=m;i++) for (int j=1;j<=m;j++)//f[j][i]表示前j格子涂i笔所能涂的最多格子。//这里要注意要后枚举格子数即j需为格子数。 { f[j][i]=0; for (int p=0;p<=j-1;p++)//枚举上一笔的结束处 { sum=tot[j]-tot[p];//p+1——j个格子中为‘0’的个数 f[j][i]=max(f[j][i],f[p][i-1]+max(j-sum-p,sum)); //f[p][i-1]指前p个格子涂i-1笔能涂得最多格子数, //max(j-sum-p,sum)指选择p+1——j这段区间内涂'0'或涂‘1’所能达到的最优值. } for (int i=1;i<=m;i++) w[k][i]=f[m][i];//w[k][i]和f[m][i]都指这块木板涂i笔时所能涂对的格子数。 } for (int i=1;i<=n;i++)//前i块木板 for (int j=1;j<=t;j++)//涂几笔 for (int k=1;k<=j;k++)//第i块木板涂k笔 if (k<=m) f2[i][j]=max(f2[i-1][j-k]+w[i][k],f2[i][j]); cout<<f2[n][t]<<endl; return 0; }