acdream1231(LCS变形+贪心)

本文介绍了一种算法,该算法通过寻找两个字符串的子序列,使得这些子序列的匹配值之和最小。通过动态规划求解最优解,并记录路径以便输出结果。适用于字符串匹配与最优化问题。

链接:点击打开链接

题意:给出一些字母两两匹配的值,给出两个串,要求再求出两个串使给出的两个串是这两个串的子序列并且匹配值最小

代码:

#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
char s1[2005],s2[2005],s3[2005];
int in[2005],out[2005],val[2005][2005],dp[2005][2005],next[2005][2005];
int main(){                                     //和poj1080几乎一样,就是加了一个路径输出
    int i,j,k,l1,l2,l3,tmp,tmp1,tmp2,tmp3,num;  //http://blog.csdn.net/stay_accept/article/details/51509685
    while(scanf("%s%s%s",s3+1,s1+1,s2+1)!=EOF){
        vector<char> a1,a2;
        l1=strlen(s1+1);
        l2=strlen(s2+1);
        l3=strlen(s3+1);
        memset(in,-1,sizeof(in));
        memset(out,-1,sizeof(out));
        memset(val,INF,sizeof(val));
        for(i=1;i<=l3;i++){
            for(j=1;j<=l3;j++){
                scanf("%d",&num);
                val[(int)s3[i]][(int)s3[j]]=num;
                if(in[(int)s3[i]]==-1||val[(int)s3[i]][in[(int)s3[i]]]>val[(int)s3[i]][(int)s3[j]])
                in[(int)s3[i]]=(int)s3[j];
                if(out[(int)s3[j]]==-1||val[out[(int)s3[j]]][(int)s3[j]]>val[(int)s3[i]][(int)s3[j]])
                out[(int)s3[j]]=(int)s3[i];
            }
        }                                       //求出每个字母与哪一个字母匹配值最小
        dp[0][0]=0;                             //和被匹配时值最小
        for(i=1;i<=l1;i++){
        dp[i][0]=dp[i-1][0]+val[(int)s1[i]][in[(int)s1[i]]];
        next[i][0]=1;
        }
        for(i=1;i<=l2;i++){
        dp[0][i]=dp[0][i-1]+val[out[(int)s2[i]]][(int)s2[i]];
        next[0][i]=2;
        }                                       //先初始化
        for(i=1;i<=l1;i++){
            for(j=1;j<=l2;j++){                 //dp[i][j]表示第一个串匹配到i,第二个串匹配到j
                tmp1=dp[i-1][j]+val[(int)s1[i]][in[(int)s1[i]]];
                tmp2=dp[i][j-1]+val[out[(int)s2[j]]][(int)s2[j]];
                tmp3=dp[i-1][j-1]+val[(int)s1[i]][(int)s2[j]];
                tmp=min(tmp1,min(tmp2,tmp3));
                dp[i][j]=tmp;
                if(tmp==tmp1)
                next[i][j]=1;
                else if(tmp==tmp2)
                next[i][j]=2;
                else
                next[i][j]=3;                   //并记录前驱
            }
        }
        printf("%d\n",dp[l1][l2]);
        while(l1>0||l2>0){
            if(next[l1][l2]==1){
                a1.push_back(s1[l1]);
                a2.push_back((char)in[(int)s1[l1]]);
                l1--;
            }
            else if(next[l1][l2]==2){
                a1.push_back((char)out[(int)s2[l2]]);
                a2.push_back(s2[l2]);
                l2--;
            }
            else if(next[l1][l2]==3){
                a1.push_back(s1[l1]);
                a2.push_back(s2[l2]);
                l1--,l2--;
            }
        }
        for(i=a1.size()-1;i>=0;i--)
        printf("%c",a1[i]);
        printf("\n");
        for(i=a2.size()-1;i>=0;i--)
        printf("%c",a2[i]);
        printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值