【题目描述】
有n条木板需要被粉刷。每条木板被分为m个格子。每个格子要被刷成红色或蓝色。
【输入描述】
每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。每个格子最多只能被粉刷一次。
如果只能粉刷t次,询问最多能正确粉刷多少格子。
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
【输出描述】
第一行包含三个整数,n、m、t。接下来有n行,每行一个长度为m的字符串,0表示红色,1表示蓝色。
【样例输入】
3 6 3
111111
000000
001100
【样例输出】
16
【数据范围及提示】
1 ≤ n,m ≤ 50,0 ≤ t ≤ 2500。
源代码: #include<cstdio> #include<algorithm> using namespace std; int n,m,T,ans(0),Sum[2501],f[2501][2501],DP[2501][2501]; //Sum[i]=该行前i个格子是1的格子的数目。 char i[2501]; int main() { scanf("%d%d%d",&n,&m,&T); for(int k=1;k<=n;k++) { scanf("%s",i+1); for (int a=1;a<=m;a++) Sum[a]=Sum[a-1]+(i[a]=='1'); for (int a=1;a<=m;a++) for(int b=1;b<=m;b++) { f[b][a]=0; //取最大值先赋最小值。 for (int c=0;c<b;c++) //可以为0,因为可以前面不走。 { int Num=Sum[b]-Sum[c]; //前缀和处理,意为[c,b]之中1的个数。 f[b][a]=max(f[b][a],f[c][a-1]+max(Num,b-c-Num)); //取0或1的正确格子数最大值。 } } for (int a=1;a<=T;a++) { int Num=min(m,a); //Num意为实际粉刷次数,在一行的格子数与粉刷次数限制中取小。 for (int b=1;b<=Num;b++) DP[k][a]=max(DP[k][a],DP[k-1][a-b]+f[m][b]); } } printf("%d",DP[n][T]); return 0; } /* 很有意思的一个划分型DP,这种类型的动态规划总是想不出来,解法又令人拍案称奇。 解题思路: 先处理当前行,设f[i][j]为该行前i个格子刷j次最多的正确格子数,则有: f[i][j]=max(f[k][j-1]+max(T1,T2)),其中k表示当前行这一次粉刷的起点,T1、T2分别表示当前区间0、1的格子数; 再进行大局处理,设DP[i][j]为前i行刷了j次的最多正确格子数,则有: DP[i][j]=max(DP[i-1][j-k]+f[m][k]),其中k表示当前行粉刷的次数。 */