String Problem(模板)【最短路】

String Problem

题目链接(点击)

Boy Valera likes strings. And even more he likes them, when they are identical. That's why in his spare time Valera plays the following game. He takes any two strings, consisting of lower case Latin letters, and tries to make them identical. According to the game rules, with each move Valera can change one arbitrary character Ai in one of the strings into arbitrary character Bi, but he has to pay for every move a particular sum of money, equal to Wi. He is allowed to make as many moves as he needs. Since Valera is a very economical boy and never wastes his money, he asked you, an experienced programmer, to help him answer the question: what minimum amount of money should Valera have to get identical strings.

Input

The first input line contains two initial non-empty strings s and t, consisting of lower case Latin letters. The length of each string doesn't exceed 105. The following line contains integer n (0 ≤ n ≤ 500) — amount of possible changings. Then follow n lines, each containing characters Ai and Bi (lower case Latin letters) and integer Wi (0 ≤ Wi ≤ 100), saying that it's allowed to change character Ai into character Bi in any of the strings and spend sum of money Wi.

Output

If the answer exists, output the answer to the problem, and the resulting string. Otherwise output -1 in the only line. If the answer is not unique, output any.

Examples

input

Copy

uayd
uxxd
3
a x 8
x y 13
d c 3

output

Copy

21
uxyd

input

Copy

a
b
3
a b 2
a b 3
b a 5

output

Copy

2
b

input

Copy

abc
ab
6
a b 4
a b 7
b a 8
c b 11
c a 3
a c 0

output

Copy

-1

思路:

·  开始看题目没看太仔细,没感觉是最短路,因为我只是考虑了上下两个字母之间转换:

         a

         b

      a→b 或者是 b→a

      没考虑到  a→c→d→e

                       b→e 这种情况

·  看懂以后就知道是模板题了,有一点不同的是:

          要将字符转换为数字表示最短路,在判断a变为什么的时候要先将a到其余25个点的最短路存进二维数组 (其余字母同理),      下面是代码:

        for(int i=1;i<=26;i++){
            diji(i);
            for(int j=1;j<=26;j++){
                if(i==j){
                    num[i][j]=0;
                }
                else{
                    num[i][j]=dis[j];
                }
            }
        }

·  想知道a最终变成什么就要判断到其余各点距离的最小值

        如果minn==MAX 即表示该点无法通过条件转化成其他字母,要输出 -1

        否则 sum+=minn 

·  但要注意:

        两次输入相同的字母关系要取最小的 进行 addnode(将两个点用链式前向星连起来)

AC代码:

#include<stdio.h>
#include<string.h>
const int MAX=1e5;
struct node{
    int to;
    int len;
    int next;
}edge[MAX+5];
int ans;
int head[MAX+5];
void addnode(int u,int v,int w)
{
    edge[ans].to=v;
    edge[ans].len=w;
    edge[ans].next=head[u];
    head[u]=ans++;
}
void allbegin()
{
    memset(head,-1,sizeof(head));
    ans=0;
}
int vis[MAX+5],dis[MAX+5];
void diji(int s)
{
    for(int i=1;i<=26;i++){
        dis[i]=MAX;
        vis[i]=0;
    }
    dis[s]=0;
    while(1){
        int k=-1,len=MAX;
        for(int i=1;i<=26;i++){
            if(!vis[i]&&len>dis[i]){
                k=i;
                len=dis[i];
            }
        }
        if(k==-1){
            break;
        }
        vis[k]=1;
        for(int j=head[k];~j;j=edge[j].next){
            int t=edge[j].to;
            if(!vis[t]&&dis[t]>edge[j].len+dis[k]){
                dis[t]=edge[j].len+dis[k];
            }
        }
    }
}            //上面是迪杰斯特拉模板
int main()
{
    int num[55][55],n;
    char a[MAX+5],b[MAX+5],c[MAX+5];
    memset(num,-1,sizeof(num));
    scanf("%s%s",a,b);
    int la=strlen(a);
    int lb=strlen(b);
    scanf("%d",&n);
    allbegin();
    for(int i=1;i<=n;i++){
        int w;
        char u[5],v[5];
        scanf("%s%s%d",u,v,&w);
        int u1=u[0]-'a'+1;
        int v1=v[0]-'a'+1;
        if(num[u1][v1]==-1||num[u1][v1]>w){
            addnode(u1,v1,w);
        }
    }
    if(la!=lb){    //长度不等 直接输出-1
        printf("-1
");
    }
    else{     //将26个字母任意两点距离打表
        for(int i=1;i<=26;i++){
            diji(i);
            for(int j=1;j<=26;j++){
                if(i==j){
                    num[i][j]=0;
                }
                else{
                    num[i][j]=dis[j];
                }
            }
        }
        int sum=0;
        for(int i=0;i<la;i++){
            int a1=a[i]-'a'+1;
            int b1=b[i]-'a'+1;
            if(a1==b1){
                c[i]=a[i];
            }
            else{  //暴力找出与两个字符 转换值之和最小的 字母(数字代表字母)
                int minn=MAX;
                for(int j=1;j<=26;j++){
                    if(num[a1][j]+num[b1][j]<minn){
                        c[i]='a'+j-1;
                        minn=num[a1][j]+num[b1][j];
                    }
                }
                if(minn==MAX){  //没有条件将其转换成其他值 结果任然是MAX 输出-1
                    printf("-1
");
                    return 0;
                }
                else{
                    sum+=minn;
                }
            }
        }
        printf("%d
",sum);
        puts(c);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ldu-xingjiahui/p/12407460.html