1468-PIPI的魔咒

题目描述:
大魔术师PIPI有N个转换魔咒,每个转换魔咒可以将一个字符串变成另一个字符串。
比如说:
“PIPI”->“POPO”
“boy”->“girl”
“boy”->“u”
“isau”->“OJ”
那么对于字符串"PIPIisaboy",大魔术师PIPI可以通过2次魔咒将"PIPIisaboy"变成"POPOisagirl"。
也可以通过2次魔咒将"PIPIisaboy"变成"PIPIOJ"。
现在你知道了PIPI的所有魔咒,想让他把字符串A变成字符串B,请输出变换所需的最少步数。
输入:
输入包含单组测试样例。
第一行输入字符串A和字符串B。1≤|A|,|B|≤30。
接下来输入一个数字N,代表转换魔咒的个数(1≤N≤10)。
接下来N行,每一行输入一个转换规则 X Y,代表可以将字符串X转化为Y。 1≤|X|,|Y|≤30。
本题给出的所有字符串均不包含空格。
输出:
如果在10次之内能将A变为B,输出从字符串A变为字符串B的最少次数。否则输出-1。
样例输入:
PIPIisaboy POPOisagirl
4
PIPI POPO
boy girl
boy u
isau OJ
样例输出:
2

题解代码如下:

#include 
using namespace std;
string s, t;
map<string, bool> st;	// 标记数组,标记字符串有没有被访问
map<string, vector<string>> trans;	// key表示原字符串,value表示用来替换的字符串
struct Node{
	string s;	// 表示当前字符串
	int t;		// 表示替换为当前字符串所需要的步数
};

int bfs() {
	queue<Node> q;
	q.push({s, 0});
	st[s] = true;

	while (q.size()) {
		auto now = q.front(); q.pop();
		if (now.t > 10) continue;	// 如果替换次数大于10则跳过
		if (now.s == t) {
			return now.t;
		}
		for (int L = 0; L < now.s.size(); L++) {	// 枚举字符串左端点
			for (int len = 1; L + len - 1 < now.s.size(); len++) { // 枚举字符串长度
				string subs = now.s.substr(L, len);		// 截取以左端点L为起点,长度为len的字符串
				if (trans.count(subs)) {	// 如果trans中存在有可替换的字符串则进行下一步
					for (int i = 0; i < trans[subs].size(); i++) {	// 遍历可替换的字符串列表
						string ns = now.s;
						ns.replace(L, len, trans[subs][i]);	// 将源字符串的字串替换掉
						if (!st[ns]) {	// 如果替换后的字符串没有被访问
							st[ns] = true;	// 访问这个字符串
							q.push({ns, now.t + 1});	// 将字符串入队
						}
					}
				}
			}
		}
	}

	return -1;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> s >> t;
	int n;
	cin >> n;
	while (n--) {
		string a, b;
		cin >> a >> b;
		trans[a].push_back(b);	// 将可替换a的所有字符串b存下来
	}

	cout << bfs() << endl;
	return 0;
}

你可能感兴趣的:(PIPIOJ,算法,bfs)