UVA - 1437 String painter

链接

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4183

题解

贪心和dp相结合
s刷到t不好想,我们先想怎么从空序列刷到t
g[i][j]表示从空序列(可以理解为一开始全是*)刷出t序列的最小花费
t[i]=t[j]时,我如果把[i,j]全刷成t[i]然后再接着刷,这样肯定最优,因为如果我不这样刷,而是先把中间刷好,再刷两头,中间的费用不会更优,刷两端的费用肯定会+1。此时g[i][j]=g[i][j1],这样转移的正确性在于,我可以构造一种把i,j1先全刷成t[i],再接着刷的方案,这个方案和上述所说的是等价的
现在求出了g[][]
我令f[i]表示s的前i个字母刷成t的前i个字母的最小花费
s[i]=t[i]时,f[i]=f[i1]
s[i]t[i]时,f[i]=min{f[k]+g[k+1][j]}

思路总结

这个题学会的新思路有:

  • 把一个题拆成两个步骤,分步完成使思维复杂度降低
  • 对于区间类型的题目,可以强制分成若干个不相邻的段进行转移

代码

//DP
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#define maxn 200
#define inf 0x3f3f3f3f
#define cl(x,y) memset(x,y,sizeof(x))
using namespace std;
int g[maxn][maxn], f[maxn];
char s[maxn], t[maxn], n;
void init()
{
    n=strlen(s+1);
    cl(g,inf), cl(f,inf);
}
void dp()
{
    int i, j, l, k;
    for(i=1;i<=n;i++)g[i][i]=1;
    for(l=2;l<=n;l++)for(i=1;i+l-1<=n;i++)
    {
        j=i+l-1;
        if(t[i]==t[j])g[i][j]=g[i][j-1];
        else for(k=i;k<j;k++)g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
    }
    f[0]=0;
    for(i=1;i<=n;i++)
    {
        if(s[i]==t[i])f[i]=f[i-1];
        else for(j=0;j<i;j++)f[i]=min(f[i],f[j]+g[j+1][i]);
    }
    printf("%d\n",f[n]);
}
int main()
{
    while(~scanf("%s%s",s+1,t+1))init(), dp();
    return 0;
}
阅读更多
版权声明:转载请注明出处 https://blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/81592930
个人分类: 一般动态规划
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭