【TOJ 1661】Solitaire【BFS】

本文介绍了一种使用进制压缩来表示棋盘状态的方法,并通过广度优先搜索(BFS)来解决在限定步数内从初始状态转换到目标状态的问题。文章详细展示了如何通过坐标变换实现棋子移动,以及如何利用哈希表来避免重复搜索。

题意:给出棋盘的起始态和终结态,问能否在8步之内使得起始态变成终结态。

思路:简单的搜索题目,关键是如何保存棋盘的状态,我这里是利用了进制压缩进行保存的。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define N (1<<24)

struct Po {
    int x, y;
    bool operator<(const Po a) const{
        if (x == a.x) return y < a.y;
        return x < a.x;
    }
};

struct P {
    Po A[4];
}s, e;

queue<P>Q;
queue<int>step;

bool F[10][10];
bool flag[N+10];
int ci[8], end, go[4][2] = {1,0, -1,0, 0,1, 0,-1};
int mark[8][8];

int tr(P a) {
    int re = 0, i;
    sort(a.A, a.A+4);
    for (i = 0;i < 4;i++) {
        re += a.A[i].x*ci[i*2]+a.A[i].y*ci[i*2+1];
    }
    return re;
}

bool ch(int x, int y) {
    return x < 0 || x >= 8 || y < 0 || y >= 8;
}

bool bfs() {
    while (!Q.empty()) Q.pop();
    while (!step.empty()) step.pop();
    memset(flag, false, sizeof(flag));
    Q.push(s);
    step.push(0);
    flag[tr(s)] = true;
    int st, i, j, tx, ty, ca = 1, tt;
    P v;
    memset(mark, 0, sizeof(mark));
    while (!Q.empty()) {
        v = Q.front();
        tt = step.front();
        step.pop();
        Q.pop();
        st = tr(v);
        if (st == end) return true;
        if (tt == 8) continue;
        ca++;
        for (i = 0;i < 4;i++) {
            mark[v.A[i].x][v.A[i].y] = ca;
        }
        for (i = 0;i < 4;i++) {
            for (j = 0;j < 4;j++) {
                tx = v.A[i].x+go[j][0], ty = v.A[i].y+go[j][1];
                if (ch(tx, ty)) continue;
                P tm = v;
                if (mark[tx][ty] != ca) {
                    tm.A[i].x = tx, tm.A[i].y = ty;
                }else {
                    tx += go[j][0], ty += go[j][1];
                    if (ch(tx, ty) || mark[tx][ty] == ca) continue;
                    tm.A[i].x = tx, tm.A[i].y = ty;
                }
                int tmst = tr(tm);
                if (flag[tmst]) continue;
                Q.push(tm), step.push(tt+1), flag[tmst] = true;
            }
        }
    }
    return false;
}

int main() {
    int i, j, x, y;
    ci[0] = 1;
    for (i = 1;i < 8;i++) ci[i] = ci[i-1]*8;
    while (~scanf("%d%d", &s.A[0].x, &s.A[0].y)) {
        memset(F, false, sizeof(F));
        for (i = 1;i < 4;i++) {
            scanf("%d%d", &s.A[i].x, &s.A[i].y);
        }
        for (i = 0;i < 4;i++) s.A[i].x--, s.A[i].y--;
        for (i = 0;i < 4;i++) {
            scanf("%d%d", &x, &y);
            e.A[i].x = x-1, e.A[i].y = y-1;
        }
        end = tr(e);
        if (bfs()) puts("YES");
        else puts("NO");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值