题目描述
已知有两个字串 A , B A,B A,B及一组字串变换的规则(至多 6 6 6个规则):
A
1
A_1
A1
−
-
−>
B
1
B_1
B1
A
2
A_2
A2
−
-
−>
B
2
B_2
B2
规则的含义为:在 A A A中的子串 A 1 A_1 A1 可以变换为 B 1 B_1 B1, A 2 A_2 A2 可以变换为 B 2 B_2 B2 ⋅ ⋅ ⋅ ··· ⋅⋅⋅。
例如:A=abcd
,B=xyz
,
变换规则为:
abc
→xu
,ud
→y
,y
→yz
则此时, A A A可以经过一系列的变换变为 B B B,其变换的过程为:
abcd
→xud
→xy
→xyz
。
共进行了 3 3 3次变换,使得 A A A变换为 B B B。
输入格式
输入格式如下:
A
A
A
B
B
B
A
1
A_1
A1
B
1
B_1
B1
A
2
A_2
A2
B
2
B_2
B2 |-> 变换规则
⋅ ⋅ ⋅ ··· ⋅⋅⋅ ⋅ ⋅ ⋅ ··· ⋅⋅⋅ /
所有字符串长度的上限为 20 20 20。
输出格式
输出至屏幕。格式如下:
若在
10
10
10步(包含
10
10
10步)以内能将
A
A
A变换为
B
B
B,则输出最少的变换步数;否则输出NO ANSWER!
输入输出样例
输入 #1 复制
abcd xyz
abc xu
ud y
y yz
输出 #1 复制
3
思路
首先,既然告诉了我们数据这么小,那么一定就是一个搜索,那么,是 d f s dfs dfs 好还是 b f s bfs bfs 好呢,因为我们要求的是最小的变换次数,所以 d f s dfs dfs 要把整张图搜完了才能得到最终答案,而 b f s bfs bfs 就只要第一次搜到就是最小变换次数了,所以,当然要用 b f s bfs bfs
代码
#include<bits/stdc++.h>
using namespace std;
string a[7],b[7];
int n;
map<string,int> f;//剪枝,如果这个字符串已经搜过了,就不用再搜了
struct zj{
string s;//当前的字符串
int k;//所用步数
};
int bfs(){
queue<zj> q;
q.push(zj{a[0],0});
while(!q.empty()){
zj x=q.front();
q.pop();
if(x.k==10)//没必要再搜了
continue;
for(int i=1;i<=n;i++){
for(int pos=x.s.find(a[i],0);pos!=-1;pos=x.s.find(a[i],pos+1)){
//a.find(b,x)表示在a这个字符串中从第x个字符寻找b这个字符串,如果没找到,返回-1
string t=x.s;
t.replace(pos,a[i].length(),b[i]);
//这个a.replace(x,len,b)表示在字符串a的第x个字符后的len个字符(包括第x个字符)替换成b这个字符串
if(!f[t]){//前面的剪枝
if(t==b[0])//找到了解
return x.k+1;
f[t]=1;//标记
q.push(zj{t,x.k+1});
}
}
}
}
return -1;//找不到
}
int main(){
while(cin>>a[n]>>b[n])
n++;
n--;//最后n比原来的n大1
int ans=bfs();
if(ans!=-1)
printf("%d",ans);
else printf("NO ANSWER!");
return 0;
}