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

次元传送门:洛谷P4158

思路

f[i][j][k][0/1]表示在坐标为(i,j)的格子 已经涂了k次 (0是此格子涂错 1是此格子涂对)涂对的格子数

显然的是 每次换行都要增加一次次数

那么当j=1时:

f[i][j][k][1]=max(f[i-1][m][k-1][1],f[i-1][m][k-1][0])+1;//可以从前一排最后一个转移过来 记得+1
f[i][j][k][0]=max(f[i-1][m][k-1][1],f[i-1][m][k-1][0]);//同理 不用+1

当j>1时分成两种情况

  • 当第i格和第i-1格相同
f[i][j][k][1]=f[i][j-1][k][1]+1;//最优为前一个不换方案即可+1 因为同色
f[i][j][k][0]=max(f[i][j-1][k][0],f[i][j-1][k-1][1]);//如果不对的话 就要从前面也错不换刷子或者前面对换刷子中取最大值
  • 当第i格和第i-1格不同
f[i][j][k][1]=max(f[i][j-1][k-1][1]+1,f[i][j-1][k][0]+1);//当前是对的可以从前面是对的但是换刷子或者前面是错的不换刷子中来 记得+1
f[i][j][k][0]=max(f[i][j-1][k][1],f[i][j-1][k-1][0]);//当前是错的可以从前面是对的不用换刷子或者前面是错的但是换刷子中来 不用+1

每次查找都要取ans

因为有可能在任意一格停下

代码

#include<iostream>
using namespace std;
#define maxn 55
int n,m,t,ans;
int map[maxn][maxn];
int f[maxn][maxn][maxn*maxn][2];
int main()
{
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++)//输入操作 
    {
        string s;
        cin>>s;
        for(int j=0;j<s.size();j++)
        map[i][j+1]=s[j]-'0';
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=1;k<=t;k++)
            {
                if(j==1)//第一排 
                {
                    f[i][j][k][1]=max(f[i-1][m][k-1][1],f[i-1][m][k-1][0])+1;
                    f[i][j][k][0]=max(f[i-1][m][k-1][1],f[i-1][m][k-1][0]);
                }
                else
                {
                    if(map[i][j]==map[i][j-1])//相同 
                    {
                        f[i][j][k][1]=f[i][j-1][k][1]+1;
                        f[i][j][k][0]=max(f[i][j-1][k][0],f[i][j-1][k-1][1]);
                    }
                    else//不同 
                    {
                        f[i][j][k][1]=max(f[i][j-1][k-1][1]+1,f[i][j-1][k][0]+1);
                        f[i][j][k][0]=max(f[i][j-1][k][1],f[i][j-1][k-1][0]);
                    }
                }
                ans=max(ans,max(f[i][j][k][1],f[i][j][k][0]));
            }
    cout<<ans;
}

猜你喜欢

转载自www.cnblogs.com/BrokenString/p/9917111.html