1. 程式人生 > >一直追尋直到哭泣之時

一直追尋直到哭泣之時

如下的 3x3 矩陣裡,x 可以與相鄰的數字交換位置。

1 2 3
x 4 6
7 5 8

遊戲目的是達到下面的局面:

1 2 3
4 5 6
7 8 x

輸入一個遊戲局面,輸出可以達成目的的操作序列(每一步 x 與哪個方向的數交換)。如果不能達到目的,輸出 unsolvable

任何一種可行的解都可以達到目的。

從目標局面反向搜尋。共計有 181440 個可以解的答案,將答案都儲存起來待之後查詢。樸素地將所有的狀態用 std::string 儲存得到了 MLE。但我不願寫康託展開,改而將位置數字壓縮到長整數中,x 以 0 表示。

到此可通過這個題。但我的資源消耗還是比較多的,可能資料量比較少每組直接搜尋可以通過吧。可以考慮康託展開壓縮空間;發現最大答案只有 31 個步驟,所以答案可以壓縮到 2x31 = 62 位的整數裡,再壓縮空間;還可以將詢問都儲存起來,搜尋的時候搜到所有的答案即停止,可以壓縮時間和空間。

#include <iostream>
#include <queue>
#include <map>
#include <unordered_map>
#include <string>
#include <functional>
#include <algorithm>
#include <cstdint>
#include <cassert>

typedef unsigned long long ull;
typedef unsigned uint;

bool GetNextCase
(std::string& s) { s.clear(); static char tmp[3]; for (int i = 0; i < 9; ++i) { std::cin >> tmp; if (!std::cin) { return false; } s += tmp[0]; } return true; } ull StagePack(std::string s) { std::reverse(s.begin(), s.end()); ull p = 0; for (int i = 0; i < 9; ++
i) { p <<= 4; if (s[i] == 'x') { p |= 0; } else { p |= s[i] - '0'; } } return p; } uint GetStagePack(ull p, int i) { return (uint) ((p >> (4 * i)) & 0xf); } ull SetStagePack(ull p, int i, ull v) { i *= 4; p = ((p & (~(ull{0xf} << i))) | (v << i)); return p; } std::string UnpackStage(ull p) { std::string s; for (int i = 0; i < 9; ++i) { int si = (int)(p & 0xf); assert(si >= 0 && si < 9); if (si == 0) { s += 'x'; } else { s += (char)('0' + si); } p >>= 4; } return s; } ull StagePackSwap(ull p, int i, int j) { uint pi = GetStagePack(p, i); uint pj = GetStagePack(p, j); p = SetStagePack(p, i, pj); p = SetStagePack(p, j, pi); return p; } struct Stage { ull stage; int xpos; }; typedef std::map<ull, std::string> SolutionMap; SolutionMap GetSolutions() { Stage initial; initial.stage = StagePack("12345678x"); initial.xpos = 8; std::queue<Stage> blob; blob.emplace(initial); SolutionMap sln; sln[initial.stage] = ""; std::array<int, 9> step[4]; { auto& lstep = step[0]; for (int i = 0; i < 9; ++i) { lstep[i] = i - 1; if (i % 3 == 0) { lstep[i] = -1; } } auto& rstep = step[1]; for (int i = 0; i < 9; ++i) { rstep[i] = i + 1; if (i % 3 == 2) { rstep[i] = -1; } } auto& ustep = step[2]; for (int i = 0; i < 9; ++i) { ustep[i] = i - 3; } auto& dstep = step[3]; for (int i = 0; i < 9; ++i) { dstep[i] = i + 3; } } char step_name[4] = {'r', 'l', 'd', 'u'}; while (!blob.empty()) { Stage curr = blob.front(); blob.pop(); int xpos = curr.xpos; for (int i = 0; i < 4; ++i) { int nxpos = step[i][xpos]; if (nxpos < 0 || nxpos >= 9) { continue; } ull stage = curr.stage; stage = StagePackSwap(stage, xpos, nxpos); auto iter_next = sln.find(stage); if (iter_next != sln.end()) { continue; } sln.emplace(stage, sln[curr.stage] + step_name[i]); Stage next{stage, nxpos}; blob.emplace(std::move(next)); } if (sln.size() > 200000) { std::cerr << "large solution size\n"; break; } } return sln; } int main() { auto sln = GetSolutions(); std::string s; while (GetNextCase(s)) { auto iter = sln.find(StagePack(s)); if (iter == sln.end()) { std::cout << "unsolvable\n"; } else { std::string res = iter->second; std::reverse(res.begin(), res.end()); std::cout << res << std::endl; } } return 0; }