zoukankan      html  css  js  c++  java
  • Software Industry Revolution----POJ3898----DP

    题目地址:http://poj.org/problem?id=3898

    题目意思:

    给你一个模式串,再给你一个原串,要你去匹配

    模式串里面的?可对应任意一个字符

    *号可对应0个或多个字符

    其中a=1,b=2....要你找出在原串中能匹配出的最小值

    如果不能就输出-1

    这是一道DP的题,其实和LCS很像,但是打比赛的时候我竟然在想各种匹配算法啊,给跪了

    尼玛DP简直就是一条不归路啊

    解题思路:

    用dp[i][j]来表示模式串的第i个和原串的第j个匹配时的值

    不能匹配就是INF

    那么有几个转移的

    对于?,dp[i][j] = dp[i-1][j-1]+cost[j]

    对于字符,如果s1[i]==s2[j],dp[i][j] = dp[i-1][j-1]+cost[j]

    对于*,因为*可以对应0个或多个

    则dp[i][j] = dp[i][j]=min{dp[i-1][k]+sum(cost[k]~cost[j])}

    对于第三种还有优化

    因为sum(cost[k]~cost[j]) = sum[j]-sum[k],所以我们用一个cur维护dp[i-1][k]-sum[k]的最小值

    然后加sum[j]就OK了,这个就直接降了一个维度下来

    实在是很妙啊,DP虽然有时候很难,但是想通了确实有美妙的地方在里面

    下面上代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 1010;
    
    char s1[maxn];
    char s2[maxn*10];
    
    int dp[maxn][maxn*10];
    int sum[maxn*10];
    const int inf = 0x3f3f3f3f;
    
    
    int main()
    {
        while(~scanf("%s%s",&s1[1],&s2[1]))
        {
            int len1 = strlen(&s1[1]);
            int len2 = strlen(&s2[1]);
    
            sum[0] = 0;
    
            for(int i=1;i<=len2;i++)
                sum[i] = sum[i-1]+(s2[i]-'a'+1);
            for(int i=0;i<=len1;i++)
                for(int j=0;j<=len2;j++)
                    dp[i][j] = inf;
    
            //对于可以做头的原串,初始化
            for(int i=0;i<=len2;i++)
            {
                if(i>0 && (s1[1]=='?' || s1[1]==s2[i]))
                    dp[1][i] = sum[i]-sum[i-1];
                else if(s1[1]=='*')
                    dp[1][i] = 0;
            }
    
            bool flag = true;
            for(int i=2;i<=len1;i++)
            {
                flag = false;
                if(s1[i]=='*')
                {
                    int cur = inf;
                    if(dp[i-1][0] == 0)
                    {
                        dp[i][0] == 0;
                        cur = 0;
                        flag = true;
                    }
                    for(int j=1;j<=len2;j++)
                    {
                        if(dp[i-1][j]-sum[j]<cur)
                            cur=dp[i-1][j] - sum[j];
                        if(cur+sum[j] < dp[i][j])
                            dp[i][j] = cur+sum[j],flag = true;
                    }
    
                }
                else
                {
                    for(int j=1;j<=len2;j++)
                    {
                        if(dp[i-1][j-1]==inf)
                            continue;
                        if(s1[i]=='?' || s2[j]==s1[i])
                        {
                            dp[i][j] = min(dp[i][j],dp[i-1][j-1]+s2[j]-'a'+1);
                            flag = true;
                        }
                    }
                }
                if(!flag)
                    break;
            }
    
            if(!flag)
            {
                puts("-1");
                continue;
            }
    
            int ans = inf;
    
            for(int i=1;i<=len2;i++)
                ans = min(ans,dp[len1][i]);
            if(ans == -1)
                puts("-1");
            else
                printf("%d
    ",ans);
    
        }
        return 0;
    }
    
    





  • 相关阅读:
    操作系统简介
    计算机基础
    Django之form
    CMDB资产采集
    Git
    User model
    多级评论
    个人主页
    media路径设置
    Web框架
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3201392.html
Copyright © 2011-2022 走看看