You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
3.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}