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 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)的更多相关文章
- POJ1475 Pushing Boxes(双搜索)
POJ1475 Pushing Boxes 推箱子,#表示墙,B表示箱子的起点,T表示箱子的目标位置,S表示人的起点 本题没有 Special Judge,多解时,先最小化箱子被推动的次数,再最小化 ...
- POJ-1475 Pushing Boxes (BFS+优先队列)
Description Imagine you are standing inside a two-dimensional maze composed of square cells which ma ...
- POJ1475 Pushing Boxes 华丽丽的双重BFS
woc累死了写了两个半小时...就是BFS?我太菜了... 刚开始以为让人预先跑一遍BFS,然后一会儿取两节加起来就好了,结果发现求出来的最短路(就是这个意思)会因箱子的移动而变化....我死了QWQ ...
- poj1475 Pushing Boxes[双重BFS(毒瘤搜索题)]
地址. 很重要的搜索题.★★★ 吐槽:算是写过的一道码量比较大的搜索题了,细节多,还比较毒瘤.虽然是一遍AC的,其实我提前偷了大数据,但是思路还是想了好长时间,照理说想了半小时出不来,我就会翻题解,但 ...
- poj1475 Pushing Boxes(BFS)
题目链接 http://poj.org/problem?id=1475 题意 推箱子游戏.输入迷宫.箱子的位置.人的位置.目标位置,求人是否能把箱子推到目标位置,若能则输出推的最少的路径,如果有多条步 ...
- poj1475 -- Pushing Boxes
这道题其实挺有趣 的,这让我想起小时候诺基亚手机上的推箱子游戏(虽然一点也不好玩) (英文不好-->) 题意翻译: 初始人(S),箱子(B),目的地(T)用人把箱子推到 T最小步数及其路径(满 ...
- POJ1475(Pushing Boxes)--bbffss
题目在这里 题目一看完就忙着回忆童年了.推箱子的游戏. 假设只有一个箱子.游戏在一个R行C列的由单位格子组成的区域中进行,每一步, 你可以移动到相邻的四个格子中的一个,前提是那个格子是空的:或者,如果 ...
- 『Pushing Boxes 双重bfs』
Pushing Boxes Description Imagine you are standing inside a two-dimensional maze composed of square ...
- POJ 1475 Pushing Boxes 搜索- 两重BFS
题目地址: http://poj.org/problem?id=1475 两重BFS就行了,第一重是搜索箱子,第二重搜索人能不能到达推箱子的地方. AC代码: #include <iostrea ...
随机推荐
- JS数据结构第一篇---算法之复杂度判断
1.算法:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作. 那么一个怎样的算法才能称得上是好算法,也就是说有没有什么标准来评判一个算法的好坏? 在此之 ...
- memcpy() 实现循环缓冲区数据的读写
使用memcpy()函数做循环缓冲区的读写 首先对mencpy函数做个简单的介绍 下面是 memcpy() 函数的声明 void *memcpy(void *str1, const void *str ...
- CentOS 6.x安装php 5.6和redis扩展的全过程
安装PHP 5.6 #yum clean all #yum update 整体升级一下yum包 #yum install -y epel-release #yum list installed | g ...
- react 中 Modal 多次使用且带参数不同实现
一.举例:对于 echatrs 的柱子分别需要弹窗 带参数 触发弹窗出现事件 showModalhref myChart.on('click', (params) => { switch (pa ...
- B树和B+树的增/删结点(转)
add by zhj: 算法其实不复杂,尤其是增加结点的算法,逻辑很简单,但有时自己想不到. 增加结点算法:首先,对于B树,没有重复结点,所以新插入的数据一定会落在叶结点上,或者说落在叶结点的所有父结 ...
- TJOI2018简要题解
Day1T1数学计算 按照时间轴建一棵线段树即可,复杂度为\(O(m \log m)\) #include <bits/stdc++.h> #define N 100005 #define ...
- CSP2019-S游记
目录 CSP2019-S游记 Day -2(UPDATE:2019-11-14) Day -1(UPDATE:2019-11-15) Day 1(UPDATE:2019-11-16) Day 2(UP ...
- 使用git svn clone迁移svn仓库(保留提交记录)
使用git svn clone迁移svn仓库 clone命令可以指定很多参数,主要用到这些,你也可以使用git svn help查看完整的参数列表. git svn clone https://172 ...
- 整理:C#中Expression表达式的妙用
原文:整理:C#中Expression表达式的妙用 一.目的:通过示例了解C#中Expression表达式的作用,通过表达式和反射可以写出很优雅的代码和架构,也可以完成一些看似不可能完成的任务 二.示 ...
- java基础 super和this
/** * super关键字的用法有三种: * 1.在子类的成员方法中,访问父类的成员变量 * 2.在子类的成员方法中,访问父类的成员方法 * 3.在子类的构造方法中,访问父类的构造方法 * * th ...