windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。 windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
标签:names bre 需要 time lan else 文件 har logs
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。 windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。 如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
输入文件paint.in第一行包含三个整数,N M T。 接下来有N行,每行一个长度为M的字符串,‘0‘表示红色,‘1‘表示蓝色。
输出文件paint.out包含一个整数,最多能正确粉刷的格子数。
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。 100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1296
分两次DP。。
dp [ i ] [ j ] [ k ] [ 0 / 1 ] 表示第 i 行,到第 j 位,已经刷了 k 次,末尾是 0 / 1 的最多正确数。。。
状态转移方程显然。。。。
然后 f [ i ] 表示刷了 i 次最多正确数。。。再做一次DP。。。具体见代码。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 60
using namespace std;
inline int Read(){
int x=0,f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
char ch;
int n,m,k;
int mp[N][N],mp0[N][N],mp1[N][N],dp[N][N][N][2],f[2600];
int main(){
n=Read();m=Read();k=Read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
mp0[i][j]=mp0[i][j-1];
mp1[i][j]=mp1[i][j-1];
ch=getchar();
while(ch!=‘0‘&&ch!=‘1‘) ch=getchar();
if(ch==‘0‘){
mp0[i][j]++;
mp[i][j]=0;
}
else {
mp1[i][j]++;
mp[i][j]=1;
}
}
int cnt=min(m,k);
for(int i=1;i<=n;i++)
for(int t=1;t<=cnt;t++)
for(int j=1;j<=m;j++){
dp[i][j][t][0]=dp[i][j-1][t][0]+(mp[i][j]==0);
dp[i][j][t][1]=dp[i][j-1][t][1]+(mp[i][j]==1);
for(int l=0;l<j;l++){
dp[i][j][t][0]=max(dp[i][j][t][0],dp[i][l][t-1][1]+mp0[i][j]-mp0[i][l]);
dp[i][j][t][1]=max(dp[i][j][t][1],dp[i][l][t-1][0]+mp1[i][j]-mp1[i][l]);
}
}
for(int i=1;i<=n;i++){
for(int j=k;j>=0;j--){
for(int l=1;l<=cnt;l++){
if(j<l) break;
f[j]=max(f[j],f[j-l]+max(dp[i][m][l][0],dp[i][m][l][1]));
}
}
}
printf("%d\n",f[k]);
return 0;
}
This passage is made by Iscream-2001.
标签:names bre 需要 time lan else 文件 har logs
原文地址:http://www.cnblogs.com/Yuigahama/p/7800319.html