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