题解 P1379 【八数码难题】

STLGirlfriend

2018-08-01 12:17:40

Solution

# 题解 BFS。将初始状态压入队列,再尝试每一种变换,同时统计移动次数,直到出现目标状态。 ## 状态的表示 这里使用 C++11 的新特性 `std::array<int, 9>` 来表示状态,为什么不使用普通数组的原因: 1. 可以直接作为队列元素类型~~(当然普通数组封装一个结构体也可以)~~。 2. 方便判重,具体见下文。 ## 判重 这里使用一个 `std::unordered_set< std::array<int, 9> >` 来判重,现在 `std::array` 的好处就体现出来了:**可以直接作为集合类型**! 当然哈希函数还是要自己写,不过也不难,把状态压成一个 $9$ 位数就可以了。 # 代码 ```c++ #include <cstdio> #include <cctype> #include <array> #include <queue> #include <unordered_set> const int StateSize = 9; const int Line = 3; const int Row = 3; typedef std::array<int, StateSize> State; const State Goal = {1, 2, 3, 8, 0, 4, 7, 6, 5}; const int DirSize = 4; const int Dx[DirSize] = {0, 1, 0, -1}; const int Dy[DirSize] = {1, 0, -1, 0}; struct Node { State st; int dist; Node(const State &st, const int &dist = 0) : st(st), dist(dist) {} }; struct StateHash { size_t operator()(const State &s) const { size_t v = 0; for (int x : s) v = v * 10 + x; return v; } }; char getGraph() { char c; while (!isgraph(c = getchar())); return c; } void readState(State &st) { for (int i = 0; i < StateSize; ++i) st[i] = getGraph() - '0'; } int main() { State st; readState(st); std::queue<Node> Q; std::unordered_set<State, StateHash> S; Q.push(Node(st)); S.insert(st); while (!Q.empty()) { Node &node = Q.front(); State &st = node.st; if (st == Goal) { printf("%d\n", node.dist); break; } int z; for (z = 0; z < StateSize; ++z) { if (!st[z]) { break; } } int x = z / Line, y = z % Row; for (int i = 0; i < DirSize; ++i) { int _x = x + Dx[i], _y = y + Dy[i]; int _z = _x * Line + _y; if (_x >= 0 && _x < Line && _y >= 0 && _y < Row) { State _st = st; _st[_z] = st[z]; _st[z] = st[_z]; if (!S.count(_st)) { S.insert(_st); Q.push(Node(_st, node.dist + 1)); } } } Q.pop(); } } ```