Files
python/TangDou/AcWing/TwoWaySearch/190_Double_Bfs_YouHua_1.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

84 lines
3.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef unordered_map<string, int> MSI;
//双向bfs a<->b
//每次需要扩展出一层,不能只扩展出一个,时间复杂度可以优化 k^10-> k^5 *2
//大概估计一下,如果单向容易超时,再改双向尝试。
const int N = 6;
int n;
string a[N], b[N];
// 功能:取出队头元素,进行n种规则扩展
// q :需要扩展的队列
// da:到起点的距离
// db:到终点的距离
// a :转换前的字符串
// b :转换后的字符串
//返回值:true false,本轮扩展,是否找到了最短步数
int extend(queue<string> &q, MSI &da, MSI &db, string a[], string b[]) {
// 取出队头元素
string t = q.front();
q.pop();
for (int i = 0; i < t.size(); i++) // 出发串的每个字符
for (int j = 0; j < n; j++) // 枚举规则
//如果t这个字符串的一段= 规则,比如= xyz,才可以替换
if (t.substr(i, a[j].size()) == a[j]) {
// 变换之后的结果r:前面不变的部分+ 变化的部分 + 后面不变的部分
// 比如abcd ,根据规则abc--> xu,变成 xud,这里的r就是xud
string r = t.substr(0, i) + b[j] + t.substr(i + a[j].size());
// r状态是否落到b里面去,两个方向会师,返回最小步数
if (db.count(r)) return da[t] + 1 + db[r];
// 如果该状态之前已扩展过,
if (da.count(r)) continue;
//没有扩展过,需要加入队列
da[r] = da[t] + 1;
q.push(r);
}
return -1;
}
// 从起点和终点来做bfs
int bfs(string A, string B) {
if (A == B) return 0;
queue<string> qa, qb; //两个方向的队列
MSI da, db; //每个状态到起点的距离da(哈希表),每个状态到终点的距离db哈希表
// qa从起点开始搜,qb从终点开始搜
qa.push(A), da[A] = 0; // 起点A到起点的距离为0
qb.push(B), db[B] = 0; // 终点B到终点B的距离为0
int t;
while (qa.size() && qb.size()) {
// 哪个方向的队列的长度更小一些,空间更小一些,从该方向开始扩展,时间复杂度比较平滑,否则有1个点会超时
if (qa.size() <= qb.size())
t = extend(qa, da, db, a, b);
else
t = extend(qb, db, da, b, a); //以b为起点理解,那么da(终点),db(起点)的概念是需要转化的,同理规则也需要b,a转化
//扩展后找到最小步数就结束
if (t > 0) break;
}
return t;
}
int main() {
//加快读入
cin.tie(0), ios::sync_with_stdio(false);
string A, B;
cin >> A >> B;
// 读入扩展规则,分别存在a数组和b数组
// 本题没有给出规则的个数,需要我们用while(cin>>str)读取,vscode中以ctrl+z结束输入。
while (cin >> a[n] >> b[n]) n++; // n记录的是规则数
//双向宽搜
int ans = bfs(A, B);
if (ans ==-1)
puts("NO ANSWER!");
else //输出最小步数
printf("%d\n", ans);
return 0;
}