http://codeforces.com/problemset/problem/33/B
给出字符串s,t;n个字母替换关系 x,y,w
题意:求使得给出两个字符串完全一致的代价,【可根据一个有向图替换字符,并消耗相应代价】
字母表比较小,预处理所有方案,(i-j替换成一致的)最优方案是反向建图的最短路,n^2 * n^2 (可做到n^3,n=26就没必要了) ,然后O(n)遍历即可
反向建图的意思: 题目要求x,y的最短一致代价,即找出一条x联通y的最短路,但是由于给的边是有向的,可能最后的结果会是 x->k,y->k 即都替换成k,但是x,y并不直接联通,这样不方便用最短路,那么直接把边的方向反过来,枚举所有点作为起点, 求min(dis[x]+dis[y]) 得到的便是实际中最短的一条路了
代码中直接n*n*(n^2)了,实际直接n*n*n也可。。。
思路很快好了,傻逼错误犯了不少。。最短路的 break写成return,外循环变量i与内部重复了,更新路径判断条件写错了。
注意:
图的权重存在为0的,应该初始化为-1而不是0!
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include<stack>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-6;
const int inf=2147483647;
char s1[100005];
char tmp[100005];
char s2[100005];
int tm[30][30];
int show[28];
int check_dis[28][28];
char check_ret[28][28];
int get_dis(int st,int a,int b)
{
int n=26;
int i;
int x=st;
int dis[30];
int vis[30];
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
for (i=1;i<=n;i++)
{
if (tm[x][i]!=-1)
dis[i]=tm[x][i];
else
dis[i]=inf;
}
vis[x]=1;
dis[x]=0;
for (int k=1;k<n;k++) //外循环变量i,与内循环变量重复,导致出现问题
{
int min_edge=inf;
int minp=-1;
for (i=1;i<=n;i++)
{
if (!vis[i]&&dis[i]<min_edge)
{
min_edge=dis[i];
minp=i;
}
}
if (minp==-1) break; //最短路写傻逼了。直接return -1;
vis[minp]=1;
for (i=1;i<=n;i++)
{
if (!vis[i]&&tm[minp][i]!=-1&&dis[i]>min_edge+tm[minp][i]) //*手误写错了
dis[i]=min_edge+tm[minp][i];
}
}
if (dis[a]==inf||dis[b]==inf) return -1;
else
return dis[a]+dis[b];
}
int get_min_dis(char a,char b,char &tt)
{
int x=a-'a'+1;
int y=b-'a'+1;
int i;
int mini=-1;
int ans=inf;
for (i=1;i<=26;i++)
{
if (!show[i]) continue;
int ret=get_dis(i,x,y);
if (ret==-1) continue;
else
{
if (ret<ans) {mini=i;ans=ret;}
}
}
if (ans==inf)
return -1;
tt=mini+'a'-1;
return ans;
}
int main()
{
int i,j;int n;
scanf("%s%s",s1,s2);
cin>>n;
getchar();
char xx,yy;
int x,y,w;
memset(tm,-1,sizeof(tm)); //权重存在为0,所以需要初始化为-1!!
for (i=1;i<=n;i++)
{
scanf("%c %c %d",&xx,&yy,&w);
getchar();
x=xx-'a'+1;
y=yy-'a'+1;
show[x]=1;
show[y]=1;
if (-1==tm[y][x])
tm[y][x]=w;
else
if (w<tm[y][x])
tm[y][x]=w;
}
int len1=strlen(s1);
int len2=strlen(s2);
if (len1!=len2)
{
printf("-1\n"); return 0;
}
for (i=1;i<=26;i++)
{
for (j=i+1;j<=26;j++)
{
char tt;
int ret=get_min_dis(i+'a'-1,j+'a'-1,tt);
check_dis[i][j]=check_dis[j][i]=ret;
check_ret[i][j]=check_ret[j][i]=tt;
}
}
strcpy(tmp,s1);
int ans=0;
for (i=0;i<len1;i++)
{
if (s1[i]==s2[i]) continue;
char tt=check_ret[s1[i]-'a'+1][s2[i]-'a'+1];
int ret=check_dis[s1[i]-'a'+1][s2[i]-'a'+1];
if (ret==-1)
{
printf("-1\n"); return 0;
}
tmp[i]=tt;
ans+=ret;
}
printf("%d\n%s\n",ans,tmp);
return 0;
}