题目链接:https://www.luogu.org/problem/P1032
题目描述
已知有两个字串A,BA,B及一组字串变换的规则(至多66个规则):
A_1A1 ->B_1B1
A_2A2 -> B_2B2
规则的含义为:在 AA中的子串 A_1A1 可以变换为B_1B1,A_2A2 可以变换为 B_2B2 …。
例如:A=abcd
,B=xyz
,
变换规则为:
abc
→xu
,ud
→y
,y
→yz
则此时,AA可以经过一系列的变换变为BB,其变换的过程为:
abcd
→xud
→xy
→xyz
。
共进行了33次变换,使得AA变换为BB。
输入格式
输入格式如下:
AA BB
A_1A1 B_1B1
A_2A2 B_2B2 |-> 变换规则
... ... /
所有字符串长度的上限为2020。
输出格式
输出至屏幕。格式如下:
若在1010步(包含1010步)以内能将AA变换为BB,则输出最少的变换步数;否则输出"NO ANSWER!"
输入输出样例
输入 #1
abcd xyz abc xu ud y y yz
输出 #1
3
题解
这是一个字符串操作的BFS。和前面做过的01迷宫和马的遍历相比,每次变化就相当于一次移动,而变换前后的字符串就相当于迷宫中的格点。使用STL中的string类进行find和replace操作还是相当方便的。在前面的例题中使用bool数组来描述是否遍历过某个格点,而这里使用一个map数组来描述是否遍历过某个字符串操作结果。下面是代码。
#include <iostream> #include <stdio.h> #include <math.h> #include <algorithm> #include <string.h> #include <map> using namespace std; struct Node { string x; int step; }; Node q[100005]; const int MAXN = 1005; int cnt = 0, step, front, rear; string n, m, a[MAXN], b[MAXN]; map<string, bool> vis; //作用等同于数组中的vis数组 int bfs() { Node now; now.x = n; now.step = 0; front = rear = 0; q[rear] = now; rear++; while(front < rear) { now = q[front++]; if(now.x == m) { cout << now.step << endl; return 0; } if(now.step > 10) { return -1; } for(int i = 0; i < cnt; i++) { string temp = now.x; int pos = temp.find(a[i]); while(pos != -1) { temp.replace(pos, a[i].length(), b[i]); //做变换 = pos if(vis[temp] == 0) { vis[temp] = true; q[rear].x = temp; q[rear].step = now.step + 1; rear++; } temp = now.x; pos = temp.find(a[i], pos + 1); // 从下一个位置查找,做一次变换 } } } return -1; } int main() { cin >> n >> m; cnt = 0; while(cin >> a[cnt] >> b[cnt]) { cnt++; } if(bfs() < 0) { cout << "NO ANSWER!" << endl; } return 0; }
程序里面另外一个需要注意的是,A字符串中可能存在多个变换的子串,我们需要每次变换其中的一个。有一个测试例是专门卡这种情况的:
abaaaba abcdaba
a b
b d
d e
e f
f g
g c