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 ...
随机推荐
- Linux内核klist链表分析
1.前言 在Linux内核的源码中,除了简洁的list链表外,内核还有klist链表,它是list链表的线程安全版本,在结构体中提供了整个链表的自旋锁,对链表节点查找.插入和删除等操作,都需要先获得这 ...
- 遍历 HashSet 的方法
遍历 HashSet 的方法 import java.util.HashSet; import java.util.Iterator; import java.util.Set; public cla ...
- DataTable 删除行 UpdateTable 方法
.不要使用DataTable.Rows.Remove(row) 而要使用 DataTable.Rows[i].Delete() .DataTable.Rows.Remove(row)相当于DataTa ...
- 钉钉的sonar集成通知
代码地址: https://gitee.com/chejiangyi/dingding-sonar 钉钉(dingding)的sonar(代码质量管理工具的)集成通知,非常简单的一个小工具. 钉钉的s ...
- 在RedisTemplate中使用scan代替keys指令
keys * 这个命令千万别在生产环境乱用.特别是数据庞大的情况下.因为Keys会引发Redis锁,并且增加Redis的CPU占用.很多公司的运维都是禁止了这个命令的 当需要扫描key,匹配出自己需要 ...
- Spring Cloud config之三:config-server因为server端和client端的健康检查导致服务超时阻塞问题
springcloud线上一个问题,当config-server连不上git时,微服务集群慢慢的都挂掉. 在入口层增加了日志跟踪问题: org.springframework.cloud.config ...
- (火狐浏览器)前端以FormData类形成表单(含文件),通过ajax提交,PHP后端iconv()报“文件名含有非法字符”且POST中的‘Ttitle’丢失
[错误信息]后端获取的POST中丢失了Ttile,文件名乱码导致iconv()出错,利用mb_detect_encoding()函数检测输入的字符串,返回false; mb_detect_encodi ...
- (一)pdf的数据类型
引自:https://blog.csdn.net/steve_cui/article/details/81912528 pdf的数据类型主要由8种 boolean(布尔型) :关键字为“ ...
- Luogu5611 Ynoi2013 D2T2/牛客挑战赛32F 最大子段和 分块、分治
传送门 之前一直咕着的,因为一些特殊的原因把这道题更掉算了-- 有一个对值域莫队+线段树的做法,复杂度\(O(n\sqrt{n} \log n)\)然而牛客机子实在太慢了没有希望(Luogu上精细实现 ...
- ArrayDeque详解
美人如斯! ArrayDeque是java中对双端队列的线性实现 一.特性 无容量大小限制,容量按需增长: 非线程安全队列,无同步策略,不支持多线程安全访问: 当用作栈时,性能优于Stack,当用于队 ...