'commit'
This commit is contained in:
84
TangDou/AcWing/TwoWaySearch/190_Double_Bfs_YouHua_1.cpp
Normal file
84
TangDou/AcWing/TwoWaySearch/190_Double_Bfs_YouHua_1.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user