这道题其实挺有趣 的,这让我想起小时候诺基亚手机上的推箱子游戏(虽然一点也不好玩)

(英文不好-->)  题意翻译:

  初始人(S),箱子(B),目的地(T)用人把箱子推到 T最小步数及其路径(满足最小步数的任何一条都可),如果不可行输出“Impossible."

思路:

  我们可以把这当作一次游戏,过程在于人推箱子,使箱子到终点并尽量快(步数小)。

于是——我们能想到:重点是箱子【人只是个辅助】

所以我们先利用bfs搜索最短迷宫路径的方式,找到箱子所到达最短路径,中间穿插 人到能推箱子的地方的最短路径bfs2

--ps:其实只有第一次搜人到推箱子处,才需要较多次的搜索。后面其实相当于人粘在箱子附近,调整方向去推箱子。所以时间复杂度是过得去的。

最后一个问题:怎么输出路径?

不要怕!!!在队列中维护string类型的路径【用结构体】。(还有一些小问题,自己去好好想想吧)

然后就很简单呐 ^_^

.......

可我调了一个晚上+一个上午,细节要注意,代码有点长,如下:

//bfs嵌套
#include<stdio.h>
#include<string.h>
#include<string>
#include<queue>
#include<iostream>
using namespace std;
const int N=25;
int n,m,t=0;
int dx[5]={0,-1,1,0},tx,ty,bbx,by;
int dy[5]={1,0,0,-1};
char ls[5]={'e','n','s','w'},bs[5]={'E','N','S','W'}; //这个能方便在最后输出路径时,让方位数组与东南西北所对应
char a[N][N];
struct node { //bfs_person队列存的结构体
int x,y; string s;
}pers;
struct boxx { //bfs_box队列所存的结构体
int x,y,xr,yr; string s;
}bx;
queue<node> q;
queue<boxx> Q;
bool fw_ok(int p,int q) { //辅助pd范围的
if(p<1||q<1||p>n||q>m) return false;
return true;
}
bool vis1[N][N],vis2[N][N];
bool bfs_person(int sx,int sy,int rx,int ry,int xzx,int xzy) { //出发点,要到达点,箱子位置
memset(vis1,0,sizeof(vis1));
vis1[sx][sy]=1; vis1[xzx][xzy]=1; //注意,人不可以站在箱子上吧
while(!q.empty()) q.pop(); //清零操作(多组数据)
node k; k.x=sx; k.y=sy; k.s="";
q.push(k);
while(!q.empty()) {
pers=q.front(); q.pop(); //这个pers是个全局变量,结束时存下了人走的路径,以便 bfs_box记录路径
if(pers.x==rx&&pers.y==ry) return true;
for(int i=0;i<4;i++) {
int xx=pers.x+dx[i],yy=pers.y+dy[i];
if(fw_ok(xx,yy)&&a[xx][yy]!='#'&&!vis1[xx][yy]) {
vis1[xx][yy]=1;
node p; p.x=xx; p.y=yy; p.s=pers.s+ls[i]; //string的特性[+直接将另一个字符串拼接在一起]
q.push(p);
}
}
}
return false; //到不了
}
bool bfs_box() { //同理
memset(vis2,0,sizeof(vis2));
while(!Q.empty()) Q.pop();
boxx k; k.x=bbx; k.y=by; k.xr=tx; k.yr=ty; k.s="";
Q.push(k); vis2[bbx][by]=true;
while(!Q.empty()) {
bx=Q.front(); Q.pop();
if(a[bx.x][bx.y]=='T') {
cout<<bx.s<<endl;
return true;
}
for(int i=0;i<4;i++) { //箱子所去方位(重要)
int xx=bx.x+dx[i],yy=bx.y+dy[i];
if(fw_ok(xx,yy)&&a[xx][yy]!='#'&&!vis2[xx][yy]) {
bool flag=bfs_person(bx.xr,bx.yr,bx.x-dx[i],bx.y-dy[i],bx.x,bx.y);
//想一想人要站在哪里才能按(dx[i],dy[i])方向推箱子:人肯定是在箱子所去方位的反方向一格(减法)[可能表达不清,自己理解一下]
if(flag) { //有可能人到不了推箱子的地方,这样就不可行了
vis2[xx][yy]=1;
boxx p; p.xr=bx.x,p.yr=bx.y,p.x=xx,p.y=yy; p.s=bx.s+pers.s+bs[i]; //这里理解了pers是全局变量的意义吧
Q.push(p);
}
}
}
}
return false;
}
int main() {
// freopen("poj1475.out","w",stdout);
while(1) {
scanf("%d%d",&n,&m);
if(!n&&!m) break;
for(int i=1;i<=n;i++) {
scanf("%s",a[i]+1);
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i][j]=='S') { tx=i,ty=j; }
else if(a[i][j]=='B') { bbx=i,by=j; }
}
}
printf("Maze #%d\n",++t);
bool flag=bfs_box();
if(!flag) printf("Impossible.\n");
cout<<endl;
}
return 0;
}

poj1475 -- Pushing Boxes的更多相关文章

  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)

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

  4. POJ1475 Pushing Boxes(BFS套BFS)

    描述 Imagine you are standing inside a two-dimensional maze composed of square cells which may or may ...

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

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

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

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

  7. POJ1475(Pushing Boxes)--bbffss

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

  8. Pushing Boxes(广度优先搜索)

    题目传送门 首先说明我这个代码和lyd的有点不同:可能更加复杂 既然要求以箱子步数为第一关键字,人的步数为第二关键字,那么我们可以想先找到箱子的最短路径.但单单找到箱子的最短路肯定不行啊,因为有时候不 ...

  9. poj 1475 || zoj 249 Pushing Boxes

    http://poj.org/problem?id=1475 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=249 Pushin ...

随机推荐

  1. CCF201403-2窗口

    问题描述 在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域.窗口的边界上的点也属于该窗口.窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的 ...

  2. linux vim编辑器使用

    小i 在光标所在行位置停止不动开始写入内容 大I 在光标所在行行首开始写入内容 小a 在光标所在行当前字符后开始写入内容 大A 在光标所在行行尾开始写入内容 小o 在光标所在行下一行开始写入内容 大O ...

  3. rem,px,em最大的区别;

    px:px像素(Pixel).相对长度单位.像素px是相对于显示器屏幕分辨率而言的.移动端的分辨率很多.所以px不适用移动端em:em的值不固定:其长度继承父级元素的字体大小rem:相对于根元素htm ...

  4. 第一阶段:Java基础之变量

    1.实例变量 #实例变量只能在类种声明,必须在构造函数.方法.任何块之外 #实例变量只能通过创建对象使用,当使用new创建对象,实例变量也同时被创建,当垃圾回收器回收对象时,实例变量也被销毁 #当在堆 ...

  5. MySql各版本

    Mysql 各个版本区别: 1.MySQL Community Server 社区版本,开源免费,但不提供官方技术支持. 2.MySQL Enterprise Edition 企业版本,需付费,可以试 ...

  6. os、sys、json、subprocess模块

    今日内容概要 1.os模块 2.sys模块 3.json模块 4.subprocess模块 今日内容详细 os模块 """该模块主要是跟操作系统打交道"&quo ...

  7. 解决pycharm的爬虫乱码问题(初步了解各种编码格式)

    Ascii码(American Standard Code for Information Interchange,美国信息互换标准代码):最初计算机只在美国使用时,只用8位的字节来组合出256(2的 ...

  8. for .. range中的坑

    最近在开发中使用了for range来遍历一个slice,结果在测试的时候遇到了bug,最后定位是错误使用for range造成的,这里记录一下: func redisSlaveScanBigKeys ...

  9. IDEA小技巧:Markdown里的命令行可以直接运行了

    作为一名开发者,相信大部分人都喜欢用Markdown来写文章和写文档. 如果你经常用开源项目或者自己维护开源项目,肯定对于项目下的README文件也相当熟悉了吧,通常我们会在这里介绍项目的功能.如何使 ...

  10. 2021.08.05 P1340 兽径管理(最小生成树)

    2021.08.05 P1340 兽径管理(最小生成树) P1340 兽径管理 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.离线化. 题意: 有n个点,m条边,每次加 ...