洛谷 题解 P4158 【[SCOI2009]粉刷匠】

状态:

dp[i][j][k][0/1]:

  1. 到达第i行时,

  2. 到达第j列时,

  3. 刷到第k次时,

  4. 这一格有没有刷对

转移

  1. 换一块木板时肯定要多刷一次
dp[i][j][k][0]=max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1]);
dp[i][j][k][1]=max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1])+1;
  1. 当前格子与上一个格子颜色相同时
/*
,最优的方式是把前一个的1状态原封不动转移,这时的0状态也跟着原封不动(贪心)
*/
dp[i][j][k][1]=dp[i][j-1][k][1]+1;//继续刷下去
dp[i][j][k][0]=dp[i][j-1][k][0];//贪心,原封不动转移
  1. 当前格子与上一个格子颜色不相同时
/*
[1]有两个选择: 一个是牺牲一次k换种颜色刷,另一个是继续上一格的颜色
[0]也要贪心,因为这一格跟上一个不一样,所以如果要继续刷错,可能是从上一次[1]原封不动过来,可能是再用一刷使得刷错.
*/
dp[i][j][k][1]=max(dp[i][j-1][k-1][1],dp[i][j-1][k][0])+1;
dp[i][j][k][0]=max(dp[i][j-1][k][1],dp[i][j-1][k-1][0]);

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,t;
char p[55][55];
int dp[55][55][2501][2];
inline int read()
{
	int tot=0;
	char c=getchar();
	while(c<'0'||c>'9')
		c=getchar();
	while(c>='0'&&c<='9')
	{
		tot=tot*10+c-'0';
		c=getchar();
	}
	return tot;
}
int main()
{
	n=read();m=read();t=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)cin>>p[i][j];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			for(int k=1;k<=t;k++)
			{
				if(j==1)
				{
					dp[i][j][k][0]=max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1]);
					dp[i][j][k][1]=max(dp[i-1][m][k-1][0],dp[i-1][m][k-1][1])+1;
					continue;
				}
				if(p[i][j]==p[i][j-1])
				{
					dp[i][j][k][1]=dp[i][j-1][k][1]+1;
					dp[i][j][k][0]=dp[i][j-1][k][0];
				}
				else
				{
					dp[i][j][k][1]=max(dp[i][j-1][k-1][1],dp[i][j-1][k][0])+1;
					dp[i][j][k][0]=max(dp[i][j-1][k][1],dp[i][j-1][k-1][0]);
				}
			}
		}
	}
	cout<<max(dp[n][m][t][1],dp[n][m][t][0])<<endl;
	return 0;
}

参考

这篇超棒的题解

posted @ 2019-05-01 13:11  hulean  阅读(211)  评论(0编辑  收藏  举报