srm 558 dv2 500pt

做了好长时间,害的苏神又跟我强调了一遍做dp的技巧。。。

首先当然要枚举stamp的长度len了,然后设dp[j]['C']表示这个位置涂成c颜色最少需要几次,假如用c[k]染第j个格子,看j的前len-1个位置合不合法,合法就是颜色和第j格相同或者是‘*’啦,如果不合法,就跳出,如果合法,就更新dp[j]['C'] = min{dp[j]['C'],dp[k]['C']+1 (j-len<k<j)};最后还有一种情况别漏了,那就是可以前j-len格的最小染色次数+1,min(dp[j-i]['R'],dp[j-i]['G'],dp[j-i]['B'])+1

代码贴出来。。

# include <cstdio>
# include <iostream>
# include <algorithm>
# include <string>
# include <cstring>
# define maxi 0xfffffff
using namespace std;
int dp[100][260];
char c[] = {'R','G','B'};
class Stamp
{
public:
    int getMinimumCost(string desiredColor, int stampCost, int pushCost)
    {
        int i,j,k,N = desiredColor.size(),ans = maxi,m;
        string s;
        for (i=0;i<N;++i) s[i+1] = desiredColor[i];
        for (i=1;i<=N;++i)
        {
            for (j=1;j<=N;++j) dp[j]['R'] = dp[j]['G'] = dp[j]['B'] = maxi;
            dp[0]['R'] = dp[0]['G'] = dp[0]['B'] = 0;
            for (j=i;j<=N;++j)
                for (k=0;k<3;++k)
                {
                    int flag = 0;
                    if (c[k]!=s[j]&&s[j]!='*') continue;
                    for (m=j-1;m>j-i;--m)
                    {
                        if (s[m]!=c[k]&&s[m]!='*')
                        {
                            dp[j][c[k]] = maxi;
                            flag = 1;
                            break;
                        }
                        dp[j][c[k]] = min(dp[j][c[k]],dp[m][c[k]]+1);
                    }
                    if (!flag) dp[j][c[k]] = min(dp[j][c[k]],min(dp[j-i]['R'],min(dp[j-i]['G'],dp[j-i]['B']))+1);
                }
            if (min(dp[N]['R'],min(dp[N]['G'],dp[N]['B']))<maxi)
                ans = min(ans,i*stampCost+min(dp[N]['R'],min(dp[N]['G'],dp[N]['B']))*pushCost);
        }
        return ans;
    }
};
View Code
原文地址:https://www.cnblogs.com/1carus/p/3371053.html