UVa 1604 Cubic Eight-Puzzle 立体八数码问题 双向BFS 状态设定

题目链接:Cubic Eight-Puzzle
题目描述:

给定一个初始状态和一个终止状态的 3 ∗ 3 3*3 33网格,网格中含有 8 8 8个立方体和一个空白,每个立方体的颜色如下:
在这里插入图片描述
需要注意的是:只会给出终止状态的立方体的顶面朝向,而初始的立方体摆放方式如下图,其中空格位置由输入的两个整数决定:
在这里插入图片描述
你每次操作可以将初始状态的一个立方体推入到空白地方,推入过程中会发生旋转,过程如下图所示:

问能否 30 30 30步以内到达目标状态。

题解:

本题的思路很简单,我们可以使用双向 B F S BFS BFS,每个非空格方格有六种状态(分别对应六个面朝上),所以我们可以用一个四位的二进制来表示一共有九个网格所以需要 36 36 36位二进制来表示一种状态。由于目标状态的侧面不确定,所以每个侧面对应两种情况,我们需要初始将所有可能的目标状态放入队列中,然后从起始状态进行搜索即可,需要注意的是,双向 B F S BFS BFS应该每次选择较小的队列进行搜索,搜索的次数为选择队列当前的大小,而不是一个队列搜索到头。
这道题目的细节比较多,推旋转后的状态一定要仔细。
同时这道题用 S T L STL STL的话常数较大,很容易超时,需要注意。

代码:

#include <bits/stdc++.h>

const int MAXN = 9;

using namespace std;

typedef pair<int, long long> State;

int x, y, ans;
long long endStatus, initStatus;
long long status[MAXN];
string s[MAXN];
queue<State> q[2];
unordered_map<long long, int> inQ, dis;


void getStatus(string &s, vector<int> &status)
{
    
    
    if (s[0] == 'E') {
    
    
        status.push_back(0);
    } else if (s[0] == 'W') {
    
    
        status.push_back(1);
        status.push_back(2);
    } else if (s[0] == 'R') {
    
    
        status.push_back(3);
        status.push_back(4);
    } else if (s[0] == 'B') {
    
    
        status.push_back(5);
        status.push_back(6);
    }
}

void initEndStatus(int p)
{
    
    
    if (p == 9) {
    
    
        endStatus = 0;
        for (int i = 0; i < 9; i++) {
    
    
            endStatus |= status[i] << (4 * i);
        }
        inQ[endStatus] = 1;
        dis[endStatus] = 0;
        q[1].push({
    
    0, endStatus});
        return;
    }
    vector<int> v;
    getStatus(s[p], v);
    for (int nowStatus : v) {
    
    
        status[p] = nowStatus;
        initEndStatus(p + 1);
    }
}

long long getInitStatus()
{
    
    
    long long initStatus = 0;
    for (int i = 0; i < 9; i++) {
    
    
        if (i / 3 == x && i % 3== y) {
    
     continue; }
        initStatus |= 1LL << (4 * i);
    }
    return initStatus;
}

void init()
{
    
    
    while (!q[0].empty()) {
    
     q[0].pop(); }
    while (!q[1].empty()) {
    
     q[1].pop(); }
    inQ.clear();
    dis.clear();
    initStatus = getInitStatus();
    initEndStatus(0);
}

void getEmptyPos(long long status, int &x, int &y)
{
    
    
    for (int i = 0; i < 9; i++) {
    
    
        if (((status >> (4 * i)) & (0b1111)) == 0) {
    
    
            x = i / 3;
            y = i % 3;
            break;
        }
    }
}

// 获取x, y位置的状态
long long getStatus(long long status, int x, int y)
{
    
    
    return (status >> (4 * (3 * x + y))) & 0b1111;
}

int dx[] = {
    
    0, 0, 1, -1};
int dy[] = {
    
    1, -1, 0, 0};

long long p[7][4] = {
    
    
    {
    
    0, 0, 0, 0},
    {
    
    5, 5, 3, 3},
    {
    
    4, 4, 6, 6},
    {
    
    6, 6, 1, 1},
    {
    
    2, 2, 5, 5},
    {
    
    1, 1, 4, 4},
    {
    
    3, 3, 2, 2}
};

long long transfer(long long status, int i)
{
    
    
    int x = 0, y = 0;
    getEmptyPos(status, x, y);
    int nx = x + dx[i];
    int ny = y + dy[i];
    if (nx < 0 || nx > 2 || ny < 0 || ny > 2) {
    
     return -1; }
    int lasP = 3 * x + y;
    int newP = 3 * nx + ny;
    long long newStatus = status;
    newStatus ^= getStatus(status, nx, ny) << (4 * newP); // 将nx, ny变为空格
    newStatus |= p[getStatus(status, nx, ny)][i] << (4 * lasP); // 将x, y填入新的状态
    return newStatus;
}

int bfs(queue<State> &q, int nowQ)
{
    
    
    int size = q.size();
    while (size--) {
    
    
        State now = q.front();
        q.pop();
        if (now.first >= 30) {
    
     continue; }
        for (int i = 0; i < 4; i++) {
    
    
            State newState;
            newState.first = now.first + 1;
            newState.second = transfer(now.second, i);
            if (newState.second == -1) {
    
     continue; }
            if (inQ.count(newState.second)) {
    
    
                if (inQ[newState.second] == 1 - nowQ) {
    
    
                    ans = dis[newState.second] + now.first + 1;
                    if (ans > 30) {
    
     ans = -1; }
                    return 0;
                } else {
    
    
                    continue;
                }
            }
            dis[newState.second] = newState.first;
            inQ[newState.second] = nowQ;
            q.push(newState);
        }
    }
    return -1;
}

void dBfs()
{
    
    
    if (inQ.count(initStatus)) {
    
    
        ans = 0;
        return;
    }
    ans = -1;
    inQ[initStatus] = 0;
    dis[initStatus] = 0;
    q[0].push({
    
    0, initStatus});
    while (!q[0].empty() && !q[1].empty()) {
    
    
        if (q[0].size() <= q[1].size()) {
    
    
            if (bfs(q[0], 0) == 0) {
    
     return; }
        } else {
    
    
            if (bfs(q[1], 1) == 0) {
    
     return; }
        }
    }
}

int main()
{
    
    
    while (cin >> x >> y && (x != 0 || y != 0)) {
    
    
        x--;
        y--;
        swap(x, y); // 习惯横着编号
        for (int i = 0; i < 9; i++) {
    
     cin >> s[i]; }
        init();
        dBfs();
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45523675/article/details/129209960