双向bfs-字串变换
题面
已知有两个字串 A, B 及一组字串变换的规则(至多 6 个规则):
A1→B1
A2→B2
…
规则的含义为:在 A 中的子串 A1 可以变换为 B1、A2 可以变换为 B2…。
例如:A=abcd B=xyz
变换规则为:
abc → xu ud → y y → yz
则此时,A 可以经过一系列的变换变为 B,其变换的过程为:
abcd → xud → xy → xyz
共进行了三次变换,使得 A 变换为 B。
输入格式
输入格式如下:
A B
A1 B1
A2 B2
… …
第一行是两个给定的字符串 A 和 B。
接下来若干行,每行描述一组字串变换的规则。
所有字符串长度的上限为 20。
输出格式
若在 10 步(包含 10 步)以内能将 A 变换为 B ,则输出最少的变换步数;否则输出 NO ANSWER!。
输入样例:
abcd xyz
abc xu
ud y
y yz
输出样例:
3
思路:
因为本题的变换步骤可能会很多,6^10次变换,有可能会超时,所以要使用双向bfs,即同时从起点和终点开始搜索,只要搜到相同的状态就算完成。实现代码如下:
#include <iostream>
#include <string>
#include <unordered_map>
#include <queue>
using namespace std;
const int N = 8;
string a[N],b[N];
string A,B;
int n;
int extend(queue<string> &q,unordered_map<string,int> &dist_a,unordered_map<string,int> &dist_b,string a[N],string b[N]){
string t = q.front();
int d = dist_a[t];
while(!q.empty()&&dist_a[q.front()]==d){
auto temp = q.front();
q.pop();
for(int i = 0;i<temp.size();i++){
for(int j = 0;j<n;j++){
if(temp.substr(i,a[j].size())==a[j]){
string r = temp.substr(0,i)+b[j]+temp.substr(i+a[j].size());
if(dist_b.count(r)) return dist_a[t]+dist_b[r]+1;
if(dist_a.count(r)) continue;
dist_a[r] = dist_a[t]+1;
q.push(r);
}
}
}
}
}
int bfs(){
if(A==B) return 0;
queue<string> qa,qb;
unordered_map<string,int> dist_a,dist_b;
qa.push(A);
qb.push(B);
dist_a[A] = 0;
dist_b[B] = 0;
int step = 0;
while(!qa.empty()&&!qb.empty()){
int x;
if(qa.size()>=qb.size()){
x = extend(qb,dist_b,dist_a,b,a);
}else{
x = extend(qa,dist_a,dist_b,a,b);
}
if(x<=10) return x;
if(++step==10) return -1;
}
return -1;
}
int main() {
cin>>A>>B;
while(cin>>a[n]>>b[n]) n++;
int step = bfs();
if(step==-1){
cout<<"NO ANSWER!"<<endl;
}
else cout<<step<<endl;
return 0;
}