AcWing 1107 魔板
阿新 • • 發佈:2022-03-03
字串\(Hash\),寬搜
三種變化需要點心思,不過還好,用心模擬一下。
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; //開小了會WA unordered_map<string, int> dist; //記錄某個字串,走沒有走過,如果走過,那麼是走了幾步到達的 unordered_map<string, pair<char, string>> pre; //記錄某個字串,它的前序操作符是ABC中的哪一個,它的前序字串是什麼 string start = "12345678"; //起始態 string ed; //目標態,需要輸入進來 string q[N]; //佇列 string A(string t) { // 交換上下兩行; /* 1 2 3 4 8 7 6 5 ==> 8 7 6 5 1 2 3 4 */ // 1234 5678---> 8765 4321 for (int i = 0; i < 4; i++) swap(t[i], t[7 - i]); return t; } string B(string t) { //將最右邊的一列插入到最左邊 /* 1 2 3 4 4 1 2 3 ==> 8 7 6 5 5 8 7 6 */ // 1234 5678 ---> 4123 6785 // 4向上冒泡,5向後冒泡 for (int i = 3; i > 0; i--) swap(t[i], t[i - 1]); for (int i = 4; i < 7; i++) swap(t[i], t[i + 1]); return t; } string C(string t) { //魔板中央對的4個數作順時針旋轉 /* 1 2 3 4 1 7 2 4 ==> 8 7 6 5 8 6 3 5 */ // 1234 5678 ---> 1724 5368 /* swap(t[1], t[2]) 1234 5678 -> 1324 5678 把第一個不匹配的數字放到合適位置上 swap(t[5], t[6]) 1324 5678 -> 1324 5768 把第二個不匹配的數字放到合適位置上 swap(t[1], t[5]) 1324 5768 -> 1724 5368 回到頭,再把第一個不匹配的數字放到合適位置上 */ swap(t[1], t[2]), swap(t[5], t[6]), swap(t[1], t[5]); return t; } void bfs() { int hh = 0, tt = -1; q[++tt] = start; while (hh <= tt) { string t = q[hh++]; if (t == ed) return; //找到即停止 string m[3]; m[0] = A(t); m[1] = B(t); m[2] = C(t); for (int i = 0; i < 3; i++) { string x = m[i]; if (!dist.count(x)) { //是不是走過? q[++tt] = x; dist[x] = dist[t] + 1; pre[x] = {'A' + i, t}; // x的前序:t,是通過'A'+i方式轉化過來的 } } } } int main() { char x; for (int i = 0; i < 8; i++) cin >> x, ed += x; //廣搜 bfs(); //輸出距離 cout << dist[ed] << endl; //輸出路徑 string res; //如果操作序列的長度大於0,則在第二行輸出字典序最小的操作序列。 if (dist[ed]) { while (ed != start) { res += pre[ed].first; //前序操作符,拼接路徑,是反的,因為從最後的狀態出發,找前序 ed = pre[ed].second; //前序字串 } reverse(res.begin(), res.end()); //翻過來 cout << res << endl; } return 0; }