题目描述
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。
windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。
如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
输入格式
第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0’表示红色,'1’表示蓝色。
输出格式
包含一个整数,最多能正确粉刷的格子数。
输入输出样例
输入 #1复制
3 6 3
111111
000000
001100
输出 #1复制
16
说明/提示
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。
100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。
解释:两次dp,首先处理出每行, d p [ i ] [ j ] [ 0 / 1 ] : dp[i][j][0/1]: dp[i][j][0/1]:从1-i,涂j种颜色,且最后一种为0/1的最多正确格子,转移的话…
最后我们再$ret[i][j]:$1-i行,用了j次最小多少,最后我们可以统计答案
#include<iostream>
#include<cstring>
#include<cstdio>
#define min(x,y) x>y?y:x
#define inf 1000000009
using namespace std;
long long n=0,m=0,t=0;
char G[103];
long long a[53][53]={0};
long long dp[53][2503][2]={0};
long long ret[53][2503]={0};
int main(){
ios::sync_with_stdio(false);
scanf("%lld%lld%lld",&n,&m,&t);
for(int ii=1;ii<=n;ii++){
memset(dp,0,sizeof(dp));
scanf("%s",G+1);
for(int i=1;i<=m;i++){
for(int j=1;j<=t;j++){
for(int k=0;k<2;k++){
if(G[i]==G[i-1]){
if(G[i]==k+'0'){
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]+1);
}else{
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]);
}
}else{
if(G[i]==k+'0'){
dp[i][j][k]=max(dp[i][j][k],max(dp[i-1][j][k]+1,dp[i-1][j-1][1-k]+1));
}else{
dp[i][j][k]=max(dp[i][j][k],max(dp[i-1][j][k],dp[i-1][j-1][1-k]));
}
}
}
}
}
for(int j=1;j<=t;j++){
a[ii][j]=m-max(dp[m][j][0],dp[m][j][1]);
}
a[ii][0]=m;
}
for(int i=1;i<=n;i++) for(int j=0;j<=t;j++) ret[i][j]=inf;
long long ans=inf;
for(int i=1;i<=n;i++){
for(int j=0;j<=t;j++){
for(int k=0;k<=j;k++){
ret[i][j]=min(ret[i][j],ret[i-1][j-k]+a[i][k]);
}
}
}
for(int i=0;i<=t;i++) ans=min(ans,ret[n][i]);
printf("%lld\n",n*m-ans);
return 0;
}