POJ 1475 双重 BFS

题意

传送门 POJ 1475 Pushing Boxes

题解

如果考虑只有箱子的场景,以坐标 ( x , y ) (x,y) (x,y) 为状态直接 B F S BFS BFS 即可;本题中还要考虑最小化箱子移动步数的情况下最小化人的步数,那么需要考虑人的位置,进一步扩展状态,以保证遍历搜索树。

箱子每一次移动,则人一定位于箱子之前的位置。将相邻的箱子与人看做一个状态,设转移的方向索引为 k k k,那么以 ( x , y , k ) (x,y,k) (x,y,k) 作为状态进行 B F S BFS BFS。每一次状态出队,枚举可能的 4 4 4 个转移方向,那么扩展的下一个状态为 ( x + d x [ i ] , y + d y [ i ] , i ) (x+dx[i],y+dy[i],i) (x+dx[i],y+dy[i],i),对应人的下一个位置为 ( x , y ) (x,y) (x,y),当前人的位置为 ( x − d x [ k ] , y − d y [ k ] ) (x-dx[k],y-dy[k]) (xdx[k],ydy[k]),那么状态转移中,人的最小步数需要一次以 ( x , y ) (x,y) (x,y) 为状态、将盒子当前位置看做障碍物的 B F S BFS BFS 进行求解。

状态转移时保证最小化箱子移动步数的情况下最小化人的步数。设目标位置为 ( t x , t y ) (tx,ty) (tx,ty),当 x = t x , y = t y x=tx,y=ty x=tx,y=ty 第一次出队时,由于 B F S BFS BFS 队列的两段性、有序性,保证箱子前两维为 ( t x , t y ) (tx,ty) (tx,ty) 且满足箱子移动步数最小的状态都被更新,而最终状态只考虑位置 ( t x , t y ) (tx,ty) (tx,ty),那么枚举状态的第 3 3 3 维,即方向,满足最小化箱子移动步数的情况下最小化人的步数的状态即答案。于是得到了一个双重 B F S BFS BFS 的算法。 B F S BFS BFS 时记录前驱状态,最后逆推箱子移动轨迹,在相邻的移动进行人的 B F S BFS BFS,最终得到移动方案。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 22
struct node
{
    int x, y, k;
} T, P, B;
const int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
const char ps[4] = {'w', 'e', 'n', 's'}, bs[4] = {'W', 'E', 'N', 'S'};
char mz[maxn][maxn], res[maxn * maxn * maxn * maxn], fst[4][maxn * maxn];
int R, C, dis[maxn][maxn], pm[maxn][maxn][4], bm[maxn][maxn][4], prep[maxn][maxn];
node preb[maxn][maxn][4];

inline bool judge(node& p)
{
    return 0 <= p.x && p.x < R && 0 <= p.y && p.y < C && mz[p.x][p.y] != '#';
}

int pbfs(node &p, node &b, node &t)
{
    memset(dis, -1, sizeof(dis));
    dis[p.x][p.y] = 0;
    mz[b.x][b.y] = '#';
    queue<node> q;
    q.push(p);
    while (!q.empty())
    {
        node cur = q.front();
        q.pop();
        if (cur.x == t.x && cur.y == t.y)
            break;
        node nxt;
        for (int i = 0; i < 4; ++i)
        {
            nxt.x = cur.x + dx[i], nxt.y = cur.y + dy[i];
            if (judge(nxt) && dis[nxt.x][nxt.y] == -1)
                dis[nxt.x][nxt.y] = dis[cur.x][cur.y] + 1, prep[nxt.x][nxt.y] = i, q.push(nxt);
        }
    }
    mz[b.x][b.y] = '.';
    return dis[t.x][t.y];
}

void bbfs()
{
    memset(pm, -1, sizeof(pm));
    memset(bm, -1, sizeof(bm));
    queue<node> q;
    for (int i = 0; i < 4; ++i)
    {
        B.k = i;
        node t;
        t.x = B.x - dx[i], t.y = B.y - dy[i];
        int d;
        if (judge(t) && (d = pbfs(P, B, t)) != -1)
        {
            bm[B.x][B.y][B.k] = 0, pm[B.x][B.y][B.k] = d, q.push(B);
            for (int k = prep[t.x][t.y]; t.x != P.x || t.y != P.y; k = prep[t.x][t.y])
                fst[i][--d] = ps[k], t.x -= dx[k], t.y -= dy[k];
        }
    }
    while (!q.empty())
    {
        node cur = q.front();
        q.pop();
        if (cur.x == T.x && cur.y == T.y)
        {
            for (int i = 0; i < 4; ++i)
                if (bm[T.x][T.y][i] == bm[T.x][T.y][cur.k] && pm[T.x][T.y][i] < pm[T.x][T.y][cur.k])
                    cur.k = i;
            int step = bm[cur.x][cur.y][cur.k] + pm[cur.x][cur.y][cur.k];
            res[step] = '\0';
            for (node tmp = cur;;)
            {
                res[--step] = bs[tmp.k];
                node p, b, t;
                b.x = tmp.x - dx[tmp.k], b.y = tmp.y - dy[tmp.k];
                t.x = b.x - dx[tmp.k], t.y = b.y - dy[tmp.k];
                tmp = preb[tmp.x][tmp.y][tmp.k];
                p.x = tmp.x - dx[tmp.k], p.y = tmp.y - dy[tmp.k];
                pbfs(p, b, t);
                for (int k = prep[t.x][t.y]; t.x != p.x || t.y != p.y; k = prep[t.x][t.y])
                    res[--step] = ps[k], t.x -= dx[k], t.y -= dy[k];
                if (tmp.x == B.x && tmp.y == B.y)
                {
                    while (step)
                        --step, res[step] = fst[tmp.k][step];
                    break;
                }
            }
            puts(res);
            return;
        }
        node nxt, tp, sp;
        sp.x = cur.x - dx[cur.k], sp.y = cur.y - dy[cur.k];
        for (int i = 0; i < 4; ++i)
        {
            nxt.x = cur.x + dx[i], nxt.y = cur.y + dy[i], nxt.k = i;
            tp.x = cur.x - dx[i], tp.y = cur.y - dy[i];
            int d;
            if (judge(nxt) && (d = pbfs(sp, cur, tp)) != -1)
                if (bm[nxt.x][nxt.y][nxt.k] == -1 || (bm[nxt.x][nxt.y][nxt.k] == bm[cur.x][cur.y][cur.k] + 1 && pm[nxt.x][nxt.y][nxt.k] > pm[cur.x][cur.y][cur.k] + d))
                    bm[nxt.x][nxt.y][nxt.k] = bm[cur.x][cur.y][cur.k] + 1, pm[nxt.x][nxt.y][nxt.k] = pm[cur.x][cur.y][cur.k] + d, preb[nxt.x][nxt.y][nxt.k] = cur, q.push(nxt);
        }
    }
    puts("Impossible.");
}

int main()
{
    int m = 0;
    while (~scanf("%d%d", &R, &C) && (R | C))
    {
        for (int i = 0; i < R; ++i)
            scanf(" %s", mz[i]);
        for (int i = 0; i < R; ++i)
            for (int j = 0; j < C; ++j)
                if (mz[i][j] == 'S')
                    P.x = i, P.y = j, mz[i][j] = '.';
                else if (mz[i][j] == 'T')
                    T.x = i, T.y = j, mz[i][j] = '.';
                else if (mz[i][j] == 'B')
                    B.x = i, B.y = j, mz[i][j] = '.';
        printf("Maze #%d\n", ++m);
        bbfs();
        putchar('\n');
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值