NC19975 [HAOI2008]移动玩具

题目链接

题目

题目描述

在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到某人心中的目标状态。

输入描述

前4行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具。
接着是一个空行。接下来4行表示玩具的目标状态,每行4个数字1或0,意义同上。

输出描述

一个整数,所需要的最少移动次数。

示例1

输入

1111
0000
1110
0010

1010
0101
1010
0101

输出

4

题解

知识点:BFS,状压。

显然用bfs,将局面压缩进 \(16\) 位的二进制,搜索起始状态到目标状态的最短路径。每次扩展所有棋子上下左右四个方向,不要忘记更改局面状态。

时间复杂度 \(O(?)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int dir[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };
int fin;
bool vis[1 << 16];
struct node {
    int state, step;
}st;

int bfs(node st) {
    queue<node> q;
    q.push(st);
    vis[st.state] = 1;
    while (!q.empty()) {
        node cur = q.front();
        q.pop();
        if (cur.state == fin) return cur.step;
        for (int i = 0;i < 4;i++) {
            for (int j = 0;j < 4;j++) {
                if (!((cur.state >> (i * 4 + j)) & 1)) continue;
                for (int k = 0;k < 4;k++) {
                    int xx = i + dir[k][0];
                    int yy = j + dir[k][1];
                    int sstate = (cur.state & ~(1 << (i * 4 + j))) | (1 << (xx * 4 + yy));
                    if (xx < 0 || xx >= 4 || yy < 0 || yy >= 4 || ((cur.state >> (xx * 4 + yy)) & 1) || vis[sstate]) continue;
                    vis[sstate] = 1;
                    q.push({ sstate,cur.step + 1 });
                }
            }
        }
    }
    return -1;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    for (int i = 0;i < 4;i++) {
        for (int j = 0;j < 4;j++) {
            char c;
            cin >> c;
            if (c == '1') st.state |= 1 << (i * 4 + j);
        }
    }
    for (int i = 0;i < 4;i++) {
        for (int j = 0;j < 4;j++) {
            char c;
            cin >> c;
            if (c == '1') fin |= 1 << (i * 4 + j);
        }
    }
    st.step = 0;
    cout << bfs(st) << '\n';
    return 0;
}
posted @ 2022-07-16 19:43  空白菌  阅读(69)  评论(0编辑  收藏  举报