题解 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;
}

参考

这篇超棒的题解

猜你喜欢

转载自www.cnblogs.com/hulean/p/10799604.html