描述

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 box which can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. Such a move is called a push. The box cannot be moved in any other way than by pushing, which means that if you push it into a corner you can never get it out of the corner again.

One of the empty cells is marked as the target cell. Your job is to bring the box to the target cell by a sequence of walks and pushes. As the box is very heavy, you would like to minimize the number of pushes. Can you write a program that will work out the best such sequence?

输入

The input contains the descriptions of several mazes. Each maze description starts with a line containing two integers r and c (both <= 20) representing the number of rows and columns of the maze.

Following this are r lines each containing c characters. Each character describes one cell of the maze. A cell full of rock is indicated by a '#' and an empty cell is represented by a '.'. Your starting position is symbolized by `S', the starting position of the box by 'B' and the target cell by 'T'.

Input is terminated by two zeroes for r and c.

输出

For each maze in the input, first print the number of the maze, as shown in the sample output. Then, if it is impossible to bring the box to the target cell, print ``Impossible.''.

Otherwise, output a sequence that minimizes the number of pushes. If there is more than one such sequence, choose the one that minimizes the number of total moves (walks and pushes). 本题没有 Special Judge,多解时,先最小化箱子被推动的次数,再最小化人移动的步数。若仍有多条路线,则按照N、S、W、E的顺序优先选择箱子的移动方向(即先上下推,再左右推)。在此前提下,再按照n、s、w、e的顺序优先选择人的移动方向(即先上下动,再左右动)。

Print the sequence as a string of the characters N, S, E, W, n, s, e and w where uppercase letters stand for pushes, lowercase letters stand for walks and the different letters stand for the directions north, south, east and west.

Output a single blank line after each test case.

样例输入

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

来源

Southwestern European Regional Contest 1997

本题数据为加强版,在原比赛或POJ AC的程序有可能只得50分

题解:

什么是bfs套bfs呢?在这题里,把人和物分开来想,用物体位置+人的方向来存储人与物之间的关系,那么人从左推物体就相当于人先走到物体的左边,然后把物体退了一下。

对人的走的计算也通过bfs来实现,所以是bfs套bfs。

代码实现容易出错,一些我想了比较久的代码都加了注释,希望对大家有所帮助。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,t;
int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
char ch[23][23],A[]={'N','S','W','E'},a[]={'n','s','w','e'};
bool vis[23][23];
string rec;
struct node {
int x,y,px,py;
string ans;
};
queue <node> q;
bool ok(int x,int y) {
return x>0 && x<=n && y>0 && y<=m && ch[x][y]!='#';
}
bool bfs2(node st,node ed) {//东西从pre推到now
rec="";
node fir;
fir.x=st.px,fir.y=st.py;
fir.ans="";
while(!q.empty()) q.pop();
q.push(fir);
memset(vis,0,sizeof vis);
while(!q.empty()) {
node now=q.front(),nxt;
q.pop();
if(now.x==st.x && now.y==st.y) {//人在物的位置了(说明物体已经被推过去了)
rec=now.ans;
return 1;
}
for(int i=0;i<4;i++) {
nxt=now;
nxt.x+=dx[i],nxt.y+=dy[i];
if(!ok(nxt.x,nxt.y) || (nxt.x==ed.x && nxt.y==ed.y) || vis[nxt.x][nxt.y]) continue;//人到物体该去的地方了,显然不行
vis[nxt.x][nxt.y]=1;
nxt.ans=now.ans+a[i];
q.push(nxt);
}
}
return 0;
}
string solve() {
node fir;
fir.ans="";
fir.x=fir.y=fir.px=fir.py=-1;
for(int i=1;i<=n && (fir.x==-1 || fir.px==-1);i++)
for(int j=1;j<=m && (fir.x==-1 || fir.py==-1);j++)
if(ch[i][j]=='B') fir.x=i,fir.y=j,ch[i][j]='.';
else if(ch[i][j]=='S') fir.px=i,fir.py=j,ch[i][j]='.';
queue <node> qq;
qq.push(fir);
bool vv[23][23][5];
memset(vv,0,sizeof vv);
string ans="Impossible.";
int cntans=0x3f3f3f3f,cnt=0x3f3f3f3f;
while(!qq.empty()) {
node now=qq.front(),nxt,pre;
qq.pop();
if(ch[now.x][now.y]=='T') {//更新答案
int cntnow=0;
for(int i=0;i<now.ans.length();i++) if(now.ans[i]>='A' && now.ans[i]<='Z') cntnow++;
if(cntnow<cntans || (cntnow==cntans && now.ans.length()<cnt)) {//题目中的排序方法
ans=now.ans;
cntans=cntnow;
cnt=now.ans.length();
}
continue;
}
for(int i=0;i<4;i++) {
nxt=now;
nxt.x+=dx[i];
nxt.y+=dy[i];
if(!ok(nxt.x,nxt.y) || vv[nxt.x][nxt.y][i]) continue;
pre=now;
if(i==0) pre.x++;
else if(i==1) pre.x--;
else if(i==2) pre.y++;
else if(i==3) pre.y--;//找到上一步状态
if(!bfs2(pre,now)) continue;
vv[nxt.x][nxt.y][i]=1;
nxt.ans=now.ans+rec;//人动
nxt.ans+=A[i];//箱子动
nxt.px=now.x;
nxt.py=now.y;
qq.push(nxt);
}
}
return ans;
}
signed main() {
while(scanf("%lld%lld",&n,&m)!=EOF && n && m) {
for(int i=1;i<=n;i++) scanf("%s",ch[i]+1);
cout << "Maze #" << ++t << '\n' << solve() << '\n' << '\n';
}
return 0;
}

POJ1475 Pushing Boxes(BFS套BFS)的更多相关文章

  1. POJ1475 Pushing Boxes(双搜索)

    POJ1475 Pushing Boxes  推箱子,#表示墙,B表示箱子的起点,T表示箱子的目标位置,S表示人的起点 本题没有 Special Judge,多解时,先最小化箱子被推动的次数,再最小化 ...

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

    Description Imagine you are standing inside a two-dimensional maze composed of square cells which ma ...

  3. POJ1475 Pushing Boxes 华丽丽的双重BFS

    woc累死了写了两个半小时...就是BFS?我太菜了... 刚开始以为让人预先跑一遍BFS,然后一会儿取两节加起来就好了,结果发现求出来的最短路(就是这个意思)会因箱子的移动而变化....我死了QWQ ...

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

    地址. 很重要的搜索题.★★★ 吐槽:算是写过的一道码量比较大的搜索题了,细节多,还比较毒瘤.虽然是一遍AC的,其实我提前偷了大数据,但是思路还是想了好长时间,照理说想了半小时出不来,我就会翻题解,但 ...

  5. poj1475 Pushing Boxes(BFS)

    题目链接 http://poj.org/problem?id=1475 题意 推箱子游戏.输入迷宫.箱子的位置.人的位置.目标位置,求人是否能把箱子推到目标位置,若能则输出推的最少的路径,如果有多条步 ...

  6. poj1475 -- Pushing Boxes

    这道题其实挺有趣 的,这让我想起小时候诺基亚手机上的推箱子游戏(虽然一点也不好玩) (英文不好-->)  题意翻译: 初始人(S),箱子(B),目的地(T)用人把箱子推到 T最小步数及其路径(满 ...

  7. POJ1475(Pushing Boxes)--bbffss

    题目在这里 题目一看完就忙着回忆童年了.推箱子的游戏. 假设只有一个箱子.游戏在一个R行C列的由单位格子组成的区域中进行,每一步, 你可以移动到相邻的四个格子中的一个,前提是那个格子是空的:或者,如果 ...

  8. 『Pushing Boxes 双重bfs』

    Pushing Boxes Description Imagine you are standing inside a two-dimensional maze composed of square ...

  9. POJ 1475 Pushing Boxes 搜索- 两重BFS

    题目地址: http://poj.org/problem?id=1475 两重BFS就行了,第一重是搜索箱子,第二重搜索人能不能到达推箱子的地方. AC代码: #include <iostrea ...

随机推荐

  1. Qt应用程序主窗口之二:拖放操作与打印文档

    一.拖放操作 对于一个实用的应用程序,不仅希望能从文件菜单中打开一个文件,更希望可以通过拖动直接将桌面上的文件拖入程序界面上来打开,就像可以将.pro文件拖入Creator中来打开整个项目一样.Qt中 ...

  2. 记录ssis的两个异常解决办法

    1.Foreach文件枚举提示变量为空的解决办法:把foreach属性窗口中的DelayValidation设置为True就可以了 2.csv导入数据库提示:无法在 unicode 和非 unicod ...

  3. Maven 教程(16)— pom.xml 文件详解

    原文地址:https://blog.csdn.net/liupeifeng3514/article/details/79733577 <project xmlns="http://ma ...

  4. 如何减少 webpack 构建 vue 项目的编译时间

    背景 我司前端项目框架主要是 vue,多个项目聚集在同一个仓库下,共用公共组件.页面.工具函数等.基于以上前提,我们需要对不同的项目分别进行打包,并解决单页应用强制刷新引起的问题,所以没有使用 vue ...

  5. [POC]微软3389远程漏洞CVE-2019-0708批量检测工具

    0x001 Win下检测 https://github.com/robertdavidgraham/rdpscan C:\Users\K8team\Desktop\rdpscan-master\vs1 ...

  6. es6和es5函数参数和arguments的差别

    注: 这里说的 es5 代表的都是非严格模式下. es6之前函数的参数不能传默认值: function fn(a, b){ console.log(a) console.log(b) } fn(2) ...

  7. char[],char *,string之间转换

    char []与char *之间转换 char []转char *:直接进行赋值即可 // char[] 转char *char str[] = "lala";char *str1 ...

  8. Prometheus 安装部署

    Prometheus 安装部署 安装版本:prometheus-2.6.1 百度云下载:https://pan.baidu.com/s/1w16lQZKw8PCHqlRuSK2i7A 提取码:lw1q ...

  9. 【题解】Luogu P5319 [BJOI2019]奥术神杖

    原题传送门 题目让我们最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒语的个数,\(w_i\)是第\(i\)个咒语的神力 看着根号和累乘不爽,我们两边同 ...

  10. C# vb .net图像合成-合成矩形

    在.net中,如何简单快捷地实现图像合成呢,比如合成文字,合成艺术字,多张图片叠加合成等等?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码 ...