题目描述
蒜头君被暗黑军团包围在一座岛上,所有通往近卫军团的路都有暗黑军团把手。幸运的是,小岛上有一扇上古之神打造的封印之门,可以通往近卫军团,传闻至今没有人能解除封印。
封印之门上有一串文字,只包含小写字母,有 kk 种操作规则,每个规则可以把一个字符变换成另外一个字符。经过任意多次操作以后,最后如果能把封印之门上的文字变换成解开封印之门的文字,封印之门将会开启。
蒜头君战斗力超强,但是不擅计算,请你帮忙蒜头君计算至少需要操作多少次才能解开封印之门。
输入格式
输入第一行一个字符串,长度不大于 10001000,只包含小写字母,表示封印之门上的文字。
输入第二行一个字符串,只包含小写字母,保证长度和第一个字符串相等,表示能解开封印之门的文字。
输入第三行一个整数 k(0 \le k \le 676)k(0≤k≤676)。
接下来 kk 行,每行输出两个空格隔开的字符 aa, bb,表示一次操作能把字符 aa 变换成字符 bb。
输出格式
如果蒜头君能开启封印之门,输出最少的操作次数。否则输出一行 -1−1。
样例输入复制
abcd
dddd
3
a b
b c
c d
样例输出复制
6
当我那天夜里看到这个题的时候,那个开心呀!!!这不是刚做完两遍的bfs吗!!!So easy!!!
结果得了 2 分!!!差点疯掉
看到答案,又看了一遍题就知道正解应该是什么了,是Floyd啊,这是26个字符之间的转换关系当做26个点的联系,转换一次即权值为1,复杂度才是26^3,稳过啊!!!
就又写了一遍,又WA了两下,彻底灰心了,看了看表,还是睡觉吧~~~
第二天早上又看了一会,通常最短路的坑是 负权边 或者 重边,wk!!!重边!!!
这里的重边指的不是真正的出现两次权值不一样覆盖(因为默认权值是 1 嘛),而是相同的点的转换
就是转换方案中出现了 a a 这样的情况,把这里改过就过了
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int _read() {
char ch = getchar();
int sum = 0;
while (!(ch >= '0' && ch <= '9'))ch = getchar();
while (ch >= '0' && ch <= '9')sum = sum * 10 + ch - 48, ch = getchar();
return sum;
}
const int inf=0x3f3f3f3f;
const int mm=30;
int mp[mm][mm];
string str,goal;
int m;
char o[2],p[2];
int n;
int res;
void floyd(){
for(int k=0;k<26;k++)
for(int i=0;i<26;i++)
for(int j=0;j<26;j++)
if(mp[i][j]>mp[i][k]+mp[k][j])
mp[i][j]=mp[i][k]+mp[k][j];
for(int i=0;i<n;i++){
if(mp[str[i]-'a'][goal[i]-'a']==inf){
res=-1;
break;
}
res+=mp[str[i]-'a'][goal[i]-'a'];
}
cout<<res<<endl;
}
int main()
{
cin>>str;
cin>>goal;
n=str.length();
for(int i=0;i<mm;i++)
for(int j=0;j<mm;j++)
mp[i][j]=i==j?0:inf;
scanf("%d",&m);
while(m--){
scanf("%s%s",o,p);
if(o[0]==p[0])
continue;//!!!!!?
mp[o[0]-'a'][p[0]-'a']=1;
}
floyd();
return 0;
}
再说一下bfs是怎么肥四,过是没有问题,应该是被T或者M了,这个题的目标很明确,直接转换,对当前字符串的其他成员没有影响,所以可以把转换关系当做边,使用最短路来求,而不是像青蛙跳杯子和密码锁那样的和字符串内部其他字符的位置交换,会产生后续影响!
但是还是要附上我的bfs代码,看一下思路还是可以的
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int _read() {
char ch = getchar();
int sum = 0;
while (!(ch >= '0' && ch <= '9'))ch = getchar();
while (ch >= '0' && ch <= '9')sum = sum * 10 + ch - 48, ch = getchar();
return sum;
}
const int inf=0x3f3f3f3f;
const int mm=0;
int n;
int m;
char o[2],p[2];
string str;
string goal;
map<string,int>mp;
vector<int>v[30];
struct node{
string s;
int step;
node(){}
node(string ss,int st):s(ss),step(st){}
};
queue<node>q;
string tmp;
int bfs(){
mp[str]=1;
q.push(node(str,0));
while(!q.empty()){
node now=q.front();
q.pop();
if(now.s==goal){
return now.step;
}
for(int i=0;i<n;i++){
int len=v[now.s[i]-'a'].size();
for(int j=0;j<len;j++){
tmp=now.s;
tmp[i]=v[now.s[i]-'a'][j]+'a';
if(mp[tmp]==1)
continue;
mp[tmp]=1;
//cout<<tmp<<endl;
q.push(node(tmp,now.step+1));
}
}
}
return -1;
}
int main()
{
cin>>str;
cin>>goal;
n=goal.length();
cin>>m;
while(m--){
scanf("%s%s",o,p);
v[o[0]-'a'].push_back(p[0]-'a');
}
if(str==goal)
cout<<0<<endl;
else{
int res=bfs();
cout<<res<<endl;
}
return 0;
}