Software Industry Revolution----POJ3898----DP

来源:互联网 发布:精通 d3.js pdf 编辑:程序博客网 时间:2024/06/06 07:11

题目地址: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\n",ans);    }    return 0;}