先直接抛题解,等下在整理啦QwQ
我们先不管列,考虑每一行,很容易想到设f[i][j]表示**当前这一行**前i个数涂j次色所能正确涂色的最多格子数
再枚举一个k(j≤k≤i),考虑当前第k个格子到第i个格子的情况
我们要分情况讨论:
1. 第i个格子必须正确的刷,那么意味着k~i所刷的颜色必须是与i相同的颜色。我们用sum来表示k~i中与i颜色相同的格子个数,那么就可以递推:
$F[i][j]=max{F[k-1][j-1]+sum}(j≤k≤i)$
2. 第i个格子错误地刷,那么意味着k~i所刷的颜色必须是与i相反的颜色(总共只有两种颜色嘻嘻嘻),仍然用sum可以递推:
$F[i][j]=max{F[k-1][j-1]+i-k+1-sum}(j≤k≤i)$
以上两个取最大值即可。
但是,这道题到这里当然还没有做完——还有列没考虑呢!
其实很简单,我们记g[i][j]表示第i行涂j次色最多能正确涂的格子数,而题目说最多能涂t次色,是不是很容易想到背包问题!
至此就结束了,当然也有不少小的细节就见程序吧(解释上面应该差不多了,故代码就不注释了)
//F[i][j] //1. F[k-1][j-1]+r //2. F[k-1][j-1]+i-k+1+r //r=k~i与i相同颜色的 //最后做背包 #include<cstdio> #include<cstring> #define MAX(x,y) (x>y?x:y) #define MIN(x,y) (x<y?x:y) const int N=55,T=2505; int n,m,t; int b[N][N],f[N][T],mx[N],g[N][T],dp[T]; int main() { scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%1d",&b[i][j]); if(j==1||b[i][j]!=b[i][j-1]) mx[i]++; } for(int l=1;l<=n;l++) { memset(f,0,sizeof(f)); for(int i=1;i<=m;i++) { for(int j=1;j<=mx[l];j++) { int r=0; for(int k=i;k>=j;k--) { if(b[l][k]==b[l][i]) r++; f[i][j]=MAX(f[i][j],f[k-1][j-1]+r); f[i][j]=MAX(f[i][j],f[k-1][j-1]+i-k+1-r); } g[l][j]=MAX(g[l][j],f[i][j]); } } } for(int i=1;i<=n;i++) for(int j=t;j>=1;j--) for(int k=1;k<=MIN(j,mx[i]);k++) dp[j]=MAX(dp[j],dp[j-k]+g[i][k]); printf("%d",dp[t]); }
时间: 2024-10-27 02:48:00