【15.4.1 Pushing Boxes】双重bfs

【15.4.1 Pushing Boxes】

想象您正站在一个二维的迷宫中,迷宫由是正方形的方格组成,这些方格可能被岩石阻塞,也可能没有。您可以向北,南,东或西一步移到下一个方格。这些移动被称为行走(walk)。

在一个空方格中放置了一个箱子,您可以挨着箱子站着,然后按这个方向推动这个箱子,这个箱子就可以被移动到一个临近的位置。这样的一个移动被称为推(push)。除了推以外,箱子不可能用其他的方法被移动,这就意味着如果您把箱子推到一个角落,您就永远不能再把它从角落中推出。

一个空格被标识为目标空格。您的任务就是通过一系列的行走和推把一个箱子推到目标方格中(如图15.4-1)。因为箱子非常重,您希望推的次数最少。您能编写一个程序来给出最佳的序列吗?

图15.4-1

输入

输入文件包含若干个迷宫的描述,每个迷宫描述的第一行给出两个整数r和c(都小于等于20),表示迷宫的行数和列数。

后面给出r行,每行有c个字符。每个字符描述迷宫的一个方格。一个塞满岩石的方格用一个‘#’表示,一个空方格用一个‘.’表示。你开始时站的位置用‘S’表示,箱子开始的位置用‘B’表示,目标方格用‘T’表示。

输入以两个为0的r和c结束。

输出

对输入的每个迷宫,第一行输出迷宫的编号,如样例输出。然后,如果不可能把箱子推到目标方格,输出“Impossible.”;否则,输出推的数目最小化的序列。如果存在多于一个的这样的序列,选择总的移动(行走和推)最小的序列。如果依然存在多于一个的这样的序列,那么任何一个序列都是可以被接受的。

输出序列是一个字符串,由字符N, S, E, W, n, s, e 和w组成,其中大写字母表示推,小写字母表示行走,不同的字母代表方向:北(north),南(south),东(east)和西(west)。

在每个测试用例处理后输出一个空行。


样例输入


样例输出


1 7

SB....T

1 7

SB..#.T

7 11

###########

#T##......#

#.#.#..####

#....B....#

#.######..#

#.....S...#

###########

8 4

....

.##.

.#..

.#..

.#.B

.##S

....

###T

0 0


Maze #1

EEEEE

Maze #2

Impossible.

Maze #3

eennwwWWWWeeeeeesswwwwwwwnNN

Maze #4

swwwnnnnnneeesssSSS

试题来源:ACM Southwestern European Regional Programming Contest 1997

在线测试:UVA 589,ZOJ 1249,POJ 1475



失误点

1. 搜索类流程:①复制→②模拟→③检验→④入队
为减少代码量,
宜用临时变量存储原状态(①②④)和更新后状态(②③④)

2. 看错题:
①错看成总步数最小(推箱子操作次数最小)。
②理解成只输出最小步数,用dfs来检验人的移动。

3. 判断是否越界可用#define来化简代码量

4. 代码是超时的,原因可能是应为过多字符串操作。


#include <iostream>
#include <cstdio>
#include <cstring>                                    //memset
#include <string>                                    //string
using namespace std;

struct cor
{ long x, y; };
struct stb
{ cor b, p; long fa, s; char c; };
struct sta
{ cor b, p; long fa, s; string c; };
const long N=25, dop=32, M=N*N*N*N;
const long d[4][3]={{-1, 0, ‘n‘}, {0, 1, ‘e‘}, {0, -1, ‘w‘}, {1, 0, ‘s‘}};
long n, m, S, hea, tai, a[N][N];
long s[N][N][N][N];
cor sb, sp, st;
sta e[M];
string str;

void Clr()
{
    long x1, x2, y1, y2;
    for (x1=1; x1<=n; x1++)
    for (y1=1; y1<=m; y1++)
    for (x2=1; x2<=n; x2++)
    for (y2=1; y2<=m; y2++)
    s[x1][y1][x2][y2]=-1;
}

#define in(val) ((1 <= val.x) && (val.x <= n) && (1 <= val.y) && (val.y <= m))
bool f[N][N];
stb ge[N*N];
bool check(cor S, cor b, cor T)
{
    cor tp, p;
    long i, k, hea, tai;
    str="";
    memset(f, 0, sizeof(f));
    hea=0; tai=1;
    ge[tai].p=S;        f[S.x][S.y]=1;
    if (S.x == T.x && S.y == T.y) return true;
    f[b.x][b.y]=1;
    while (hea < tai)
    {
        hea++;
        p=ge[hea].p;
        for (i=0; i<4; i++)
        {
            tp.x=p.x+d[i][0];    tp.y=p.y+d[i][1];
            if (in(tp) && f[tp.x][tp.y] == 0 && a[tp.x][tp.y] == 0)
            {
                tai++;
                ge[tai].p=tp;        f[tp.x][tp.y]=1;
                ge[tai].fa=hea;        ge[tai].c=d[i][2];
                if (tp.x == T.x && tp.y == T.y)
                {
                    k=tai;
                    while (k > 1)
                    {
                        str=ge[k].c+str;
                        k=ge[k].fa;
                    }
                    return true;
                }
            }
        }
    }
    return false;
}

long Work()
{
    long i;
    cor b, p, tb, tp, T;
    hea=0; tai=1;
    e[tai].b=sb; e[tai].p=sp;
    s[sp.x][sp.y][sb.x][sb.y]=0;
    while (hea < tai)
    {
        hea++;
        b=e[hea].b; p=e[hea].p;
        for (i=0; i<4; i++)
        {
            T.x=b.x-d[i][0];        T.y=b.y-d[i][1];
            if (in(T) && check(p, b, T))
            {
                tp.x=b.x;                tp.y=b.y;
                tb.x=b.x+d[i][0];    tb.y=b.y+d[i][1];
                if (in(tb) && a[tb.x][tb.y] == 0 &&
                    s[tp.x][tp.y][tb.x][tb.y] == -1)
                {
                    tai++;
                    e[tai].b=tb;    e[tai].p=tp;
                    e[tai].fa=hea;        e[tai].c=str+(char)(d[i][2]-32);
                    e[tai].s=e[hea].s+1;
                    s[tp.x][tp.y][tb.x][tb.y]=e[tai].s;
                    if (tb.x == st.x && tb.y == st.y)
                        return e[tai].s;
                }
            }
        }
    }
    return -1;
}

void print(long x)
{
    if (x == 1) return ;
    print(e[x].fa);
    cout << e[x].c;
}

int main()
{
    long i, j, ci=0;;
    ios::sync_with_stdio(false);
//    freopen("input.in", "r", stdin);
    cin >> n >> m;
    while (n > 0 && m > 0)
    {
        ci++;
        for (i=1; i<=n; i++)
        {
            cin >> str; str=‘ ‘+str;
            for (j=1; j<=m; j++)
            {
                if (str[j] == ‘#‘)
                {    a[i][j]=1; continue; }
                a[i][j]=0;
                if (str[j] == ‘S‘)
                    sp.x=i, sp.y=j;
                if (str[j] == ‘B‘)
                    sb.x=i, sb.y=j;
                if (str[j] == ‘T‘)
                    st.x=i, st.y=j;
            }
        }
        Clr();
        S=Work();
        cout << "Maze #" << ci << ‘\n‘;
        if (S == -1) cout << "Impossible.\n\n";
        else
        {
            print(tai);
            cout << "\n\n";
        }
        cin >> n >> m;
    }
    return 0;
}
时间: 2024-10-10 14:46:39

【15.4.1 Pushing Boxes】双重bfs的相关文章

poj1475 Pushing Boxes[双重BFS(毒瘤搜索题)]

地址. 很重要的搜索题.★★★ 吐槽:算是写过的一道码量比较大的搜索题了,细节多,还比较毒瘤.虽然是一遍AC的,其实我提前偷了大数据,但是思路还是想了好长时间,照理说想了半小时出不来,我就会翻题解,但是这次总觉得自己快想出来了结果磕了两个小时才想到正解上.嘛主要还是我太弱了QwQ. 题目内容很简单.给一张图20*20,推箱子,求推动次数最少的路径,有推动次数相同方案时输出走路次数最少的路径. 乍一看这题觉得很棘手.箱子在动,人还要来回跑来跑去,虽然可以感觉出来是搜索题,但怎么搜?DFS效率太低明

POJ-1475 Pushing Boxes (BFS+优先队列)

Description Imagine you are standing inside a two-dimensional maze composed of square cells which may or may not be filled with rock. You can move north, south, east or west one cell at a step. These moves are called walks. One of the empty cells con

poj1475 Pushing Boxes(BFS)

题目链接 http://poj.org/problem?id=1475 题意 推箱子游戏.输入迷宫.箱子的位置.人的位置.目标位置,求人是否能把箱子推到目标位置,若能则输出推的最少的路径,如果有多条步数相同的推的最少的路径,则输出总步数(人走的步数+推箱子的步数)最少的那条路径:若不能把箱子推到目标位置,则输出Impossible. 思路 先求出箱子到目标位置的最短路径(bfs_box),在bfs1推箱子的过程中,根据推的方向和箱子的位置得到人的位置,再求得人到达这个位置的最短路(bfs_per

poj 1475 Pushing Boxes

http://poj.org/problem?id=1475 Pushing Boxes Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 4662   Accepted: 1608   Special Judge Description Imagine you are standing inside a two-dimensional maze composed of square cells which may or

HDU 1475 Pushing Boxes

Pushing Boxes Time Limit: 2000ms Memory Limit: 131072KB This problem will be judged on PKU. Original ID: 147564-bit integer IO format: %lld      Java class name: Main Special Judge Imagine you are standing inside a two-dimensional maze composed of sq

Pushing Boxes(广度优先搜索)

题目传送门 首先说明我这个代码和lyd的有点不同:可能更加复杂 既然要求以箱子步数为第一关键字,人的步数为第二关键字,那么我们可以想先找到箱子的最短路径.但单单找到箱子的最短路肯定不行啊,因为有时候不能被推动,怎样确定一条既满足最短又满足可行的箱子路径呢,其实这就是一种有限制的BFS. 对于箱子: 设现在的位置为x,y,扩展方向为dx,dy,将要到达的下一个位置为x+dx,y+dy check它是否可行: 1.不越界. 2.之前没有走过. 3.不能走到“#”上. 4.人能够从当前站立的位置到达(

UVA 657-The die is cast(双重BFS)

InterGames is a high-tech startup company that specializes in developing technology that allows users to play games over the Internet. A market analysis has alerted them to the fact that games of chance are pretty popular among their potential custom

【POJ 1475】 Pushing Boxes

[题目链接] http://poj.org/problem?id=1475 [算法] 双重BFS [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #incl

POJ1475 Pushing Boxes(BFS套BFS)

描述 Imagine you are standing inside a two-dimensional maze composed of square cells which may or may not be filled with rock. You can move north, south, east or west one cell at a step. These moves are called walks. One of the empty cells contains a b