已知有两个字串 A, B 及一组字串变换的规则(至多 66 个规则):
A1→B1
A2→B2
…
规则的含义为:在 A 中的子串 A1A1 可以变换为 B1、A2 可以变换为 B2…。
例如:A=abcd
B=xyz
变换规则为:
abc
→→ xu
ud
→→ y
y
→→ yz
则此时,AA 可以经过一系列的变换变为 BB,其变换的过程为:
abcd
→→ xud
→→ xy
→→ xyz
共进行了三次变换,使得 AA 变换为 BB。
注意,一次变换只能变换一个子串,例如 AA=aa
BB=bb
变换规则为:
a
→→ b
此时,不能将两个 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
// 包含必要的头文件
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>// 使用标准命名空间
using namespace std;// 定义常量N,表示最多处理的字符串对数
const int N = 6;// n表示实际输入的字符串对数,A和B为初始和目标字符串
int n;
string A, B;
// a数组和b数组分别存储输入的字符串对
string a[N], b[N];/*** extend函数用于从当前队列中扩展新的字符串,尝试从a变换到b* @param q 队列,存储待处理的字符串* @param da 存储从起始字符串到当前字符串的变换次数* @param db 存储从目标字符串到当前字符串的变换次数* @param a 字符串对中的起始字符串数组* @param b 字符串对中的目标字符串数组* @return 如果找到解,则返回变换次数,否则返回11*/
int extend(queue<string>& q, unordered_map<string, int>&da, unordered_map<string, int>& db, string a[N], string b[N])
{// d表示当前处理的字符串的变换次数int d = da[q.front()];// 遍历队列中所有变换次数为d的字符串while (q.size() && da[q.front()] == d){auto t = q.front();q.pop();// 尝试将字符串t中的a[i]替换为b[i]for (int i = 0; i < n; i ++ )for (int j = 0; j < t.size(); j ++ )if (t.substr(j, a[i].size()) == a[i]){// r表示替换后的字符串string r = t.substr(0, j) + b[i] + t.substr(j + a[i].size());// 如果在反向搜索中已经处理过r,则表示找到了解if (db.count(r)) return da[t] + db[r] + 1;// 如果当前方向已经处理过r,则跳过if (da.count(r)) continue;// 更新r的变换次数,并将其加入队列da[r] = da[t] + 1;q.push(r);}}// 如果没有找到解,则返回11return 11;
}/*** bfs函数使用双向BFS搜索,尝试找到从A变换到B的最少次数* @return 如果找到解,则返回变换次数,否则返回-1*/
int bfs()
{// 如果A和B相同,则不需要变换,返回0if (A == B) return 0;// 定义两个队列,分别用于正向和反向搜索queue<string> qa, qb;// 定义两个哈希表,分别存储正向和反向搜索的字符串变换次数unordered_map<string, int> da, db;// 初始化队列和哈希表qa.push(A), qb.push(B);da[A] = db[B] = 0;// step表示当前的变换次数int step = 0;// 当两个队列都不为空时,继续搜索while (qa.size() && qb.size()){int t;// 选择较小的队列进行扩展if (qa.size() < qb.size()) t = extend(qa, da, db, a, b);else t = extend(qb, db, da, b, a);// 如果找到了解,则返回变换次数if (t <= 10) return t;// 如果变换次数超过10,则表示无法找到解,返回-1if ( ++ step == 10) return -1;}// 如果没有找到解,则返回-1return -1;
}/*** main函数为程序的入口点* @return 程序的退出状态*/
int main()
{// 输入初始和目标字符串cin >> A >> B;// 输入字符串对,直到输入结束while (cin >> a[n] >> b[n]) n ++ ;// 使用bfs函数寻找解int t = bfs();// 如果没有找到解,则输出"NO ANSWER!"if (t == -1) puts("NO ANSWER!");// 否则输出变换次数else cout << t << endl;// 程序正常退出return 0;
}