題目鏈接: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
浙公網安備 33010602011771號