[Luogu1379]八数码难题

description:
9宫格, 其中有一个空位(0), 每次操作可以将一个与空位临接的数与空位交换, 问最少需要多少次达到目标123804765(实际上是12345678顺序围了一圈中间放0~)(像不像21世纪10年代手机里的拼图小游戏?)
solution:
先手打一个临接表存储可能的状态转移:(用二维数组加 dx[],dy[] 也差不多)

const int [9][5] = {
    {2,1,3},
    {3,0,2,4},
    {2,1,5},
    {3,0,4,6},
    {4,1,3,5,7},
    {3,2,4,8},
    {2,3,7},
    {3,4,6,8},
    {2,5,7}
};

起点输入明确, 目标状态唯一已知, 因此考虑双向bfs.比较容易实现的一种方法是两个点轮流扩展, 并且用hash避免重复.这里的hash_map有一点技巧性:
把aim的导出节点分成一类vis=1, 把a(input)的导出节点分成一类vis=2.

双起点的强大在于:\(2^{\frac{k}{2}+1} = o(2^k)\)
code:

#include<cstdio>
#include<unordered_map>
#include<queue>
using namespace std;
unordered_map<int, int> vis;
unordered_map<int, int> step;
const int aim = 123804765;
int a;
const int t[9][5] = {
    {2,1,3},
    {3,0,2,4},
    {2,1,5},
    {3,0,4,6},
    {4,1,3,5,7},
    {3,2,4,8},
    {2,3,7},
    {3,4,6,8},
    {2,5,7}
};
inline void swap(int& a, int& b) {
    int t = a;
    a = b, b = t;
}
inline int read() {
    int tot = 0;
    for (int i = 0; i < 9; ++i) 
        tot = (tot << 1) + (tot << 3) + getchar() - '0';
    return tot;
}
inline int _hash(int* a) {
    int tot = 0;
    for (int i = 8; i >= 0; --i)
        tot = (tot << 1) + (tot << 3) + a[i];
    return tot;
}
inline int rehash(int a, int *arr) {
    int pos;
    for (int i = 0; i < 9; ++i) {
        arr[i] = a % 10;
        a /= 10;
        if (!arr[i])pos = i;
    }
    return pos;
}
inline void bfs() {
    if (a == aim) {
        puts("0");
        return;
    }
    int tmp[9];
    queue<int> q;
    q.push(a);
    q.push(aim);
    vis[a] = 1, vis[aim] = 2;
    step[a] = 0, step[aim] = 1;
    int cur, last;
    while (!q.empty()) {
        last = q.front();
        q.pop();
        int x0 = rehash(last, tmp);
        for (int i = 1; i <= t[x0][0]; ++i) {
            int xn = t[x0][i];
            swap(tmp[xn], tmp[x0]);
            cur = _hash(tmp);
            if (vis[cur] == vis[last]) {
                swap(tmp[xn], tmp[x0]);
                continue;
            }
            if (vis[cur] + vis[last] == 3) {
                printf("%d\n", step[cur] + step[last]);
                return;
            }
            vis[cur] = vis[last];
            step[cur] = step[last] + 1;
            q.push(cur);
            swap(tmp[xn], tmp[x0]);
        }
    }
}
int main() {
    a = read();
    bfs();
}
posted @ 2021-03-03 08:27  _dwt  阅读(51)  评论(0)    收藏  举报