题目地址:
https://www.acwing.com/problem/content/description/192/
已知有两个字串
A
A
A,
B
B
B及一组字串变换的规则(至多
6
6
6个规则):
A
1
→
B
1
A_1→B_1
A1→B1
A
2
→
B
2
A_2→B_2
A2→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"
共进行了三次变换,使得
A
A
A变换为
B
B
B。
输入格式:
输入格式如下:
A
B
A\ B
A B
A
1
B
1
A_1\ B_1
A1 B1
A
2
B
2
A_2\ B_2
A2 B2
…
…
… …
……
第一行是两个给定的字符串
A
A
A和
B
B
B。接下来若干行,每行描述一组字串变换的规则。所有字符串长度的上限为
20
20
20。
输出格式:
若在
10
10
10步(包含
10
10
10步)以内能将
A
A
A变换为
B
B
B,则输出最少的变换步数;否则输出NO ANSWER!
。
可以用双向BFS。每次考虑出队的时候,可以将元素较少的那个队列先进行扩展。代码如下:
#include <iostream>
#include <queue>
#include <unordered_set>
using namespace std;
const int N = 6;
string a[N], b[N];
int n;
bool one_step(queue<string> &qa, unordered_set<string> &sa, unordered_set<string> &sb, string a[], string b[]) {
for (int sz = qa.size(); sz; sz--) {
string s = qa.front();
qa.pop();
for (int i = 0; i < s.size(); i++)
for (int j = 0; j < n; j++)
if (i + a[j].size() <= s.size() && s.substr(i, a[j].size()) == a[j]) {
string ne = s.substr(0, i) + b[j] + s.substr(i + a[j].size());
if (sb.count(ne)) return true;
if (sa.count(ne)) continue;
sa.insert(ne);
qa.push(ne);
}
}
return false;
}
int bfs(string &A, string &B) {
if (A == B) return 0;
queue<string> qa, qb;
unordered_set<string> visa, visb;
qa.push(A);
visa.insert(A);
qb.push(B);
visb.insert(B);
int step = 0;
while (qa.size() && qb.size()) {
step++;
if (step > 10) break;
if (qa.size() <= qb.size()) {
if (one_step(qa, visa, visb, a, b)) return step;
} else if (one_step(qb, visb, visa, b, a)) return step;
}
return 11;
}
int main() {
string A, B;
cin >> A >> B;
while (cin >> a[n] >> b[n]) {
n++;
if (n == 6) break;
}
int step = bfs(A, B);
if (step > 10) puts("NO ANSWER!");
else printf("%d\n", step);
return 0;
}
时间复杂度 O ( V + E ) O(V+E) O(V+E)。