poj1475 Pushing Boxes[双重BFS(毒瘤搜索题)]
地址。
很重要的搜索题。★★★
吐槽:算是写过的一道码量比较大的搜索题了,细节多,还比较毒瘤。虽然是一遍AC的,其实我提前偷了大数据,但是思路还是想了好长时间,照理说想了半小时出不来,我就会翻题解,但是这次总觉得自己快想出来了结果磕了两个小时才想到正解上。嘛主要还是我太弱了QwQ。
题目内容很简单。给一张图20*20,推箱子,求推动次数最少的路径,有推动次数相同方案时输出走路次数最少的路径。
乍一看这题觉得很棘手。箱子在动,人还要来回跑来跑去,虽然可以感觉出来是搜索题,但怎么搜?DFS效率太低明显不行的,先排除。那就剩BFS。但是,两个对象,还要维护步数和推数两个玩意儿,还是很棘手。模拟了一下人玩推箱子的过程,发现有一个规律:除了第一次人是奔着箱子去的,其他时候总是人推了箱子后要么继续推要么到箱子另一个方向继续推的。所以时时刻刻人和箱子总是黏在一起的,或者走一点路到另一个方向再“黏”上去。这样就可以把人和箱子作为整体看了。然后就有了记录推数的数组。$pus[x][y][dir]$表示人在坐标$(x,y)$处准备推他上/下/左/右边$(dir=0~3)$的箱子前已推的次数,$walk[x][y][dir]$维护当下已行步数。队列维护一个推数单调增的队列以保证最先求得答案。每次取队头先推一下,记下当前已推次数,拓展的时候就枚举方向看可不可以从箱子新位置四周推动。可以就将这种状态压入队尾,准备下次开推。以上是粗略描述。下面记一下诸多细节。
- 队列存的是三元组x,y,dir. 每次用最新的推动情况来拓展后面的状况。有两种情形:1、继续向前推:没什么好说的;2、到箱子其他方向推:也需判断能不能推动,可不可以到,可以的话就把现在的步数和推数赋值给他,进队。
- 当考虑到箱子其他方向上推时,因为需要了解此处到彼处的最短路程,每次,箱子的位置不能通行,所以每个点在每次拓展四个方向前要先跑一次图。因为状态最多$20*20*4=1600$个(每个点每个朝向),所以总共跑图不会昊太多时间。
- 既然提到队列中状态数量不会超过1600,就要避免重复或无效推动。即我推过来又推回去,或者现在推的状态以前已经拓展过了等等。处理方法:拓展时看四个方向的推法有没有被算过,有的话是不是比当前推动的次数少,少的话就不用了。次数相同表明是我现在同一层拓展出来的产物,那就要看谁到这个状态的步行次数少了。如果没算过,直接赋值入队。又因为该状态是在下一层的,这一层所有状态都有可能去更新到他,所以该状态在取出前一定是最优解。这样同时保证了不会推来推去和冗余重复,后面的效仿前面的。
- 注意队列只是推数单调,步数并不单调。所以我找到目标后要等这一层全拓展完看哪个步数少。
- 有可能我推了之后的状态以前有过次数更少的,直接不算了(见line48,如转圈)
- 寻路过程还具体看code。其实框架还基本差不多。
- 关于输出路径:行走过程不太好记,所以索性不记了,只记箱子推动的路径(code里面的las),las[x][y][dir]表示将要向dir推的当下坐标上一次是在哪儿向哪边推的。这个想想就明白了。中间的行走路径就再跑一边BFS即可,所以是一个推动和走路穿插的串。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define mst(a,x) memset(a,x,sizeof a)
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+,INF=0x3f3f3f3f;
const int dx[]={-,,,},dy[]={,,-,};
const char d[]={'N','S','W','E'};
int mp[N][N],dis[N][N],n,m,bx,by,sx,sy,tx,ty;
#define xx x+dx[i]
#define yy y+dy[i]
queue<pii> Q;
inline void find_way(int X,int Y,int bX,int bY){
mp[bX][bY]=;mst(dis,INF);dis[X][Y]=,Q.push(make_pair(X,Y));
while(!Q.empty()){
int x=Q.front().first,y=Q.front().second;Q.pop();
for(register int i=;i<;++i)if(!mp[xx][yy]&&dis[xx][yy]>dis[x][y]+)dis[xx][yy]=dis[x][y]+,Q.push(make_pair(xx,yy));
}
mp[bX][bY]=;
}
#undef xx
#undef yy
int pus[N][N][],walk[N][N][],vis[N][N][],pre[N][N][],flag,ansx,ansy,ansdir,answ;
pair<pii,int> las[N][N][];
inline void start_pushing(){
find_way(sx,sy,bx,by);queue<pair<pii,int> > q;
mst(pus,INF),mst(walk,INF),mst(vis,);answ=INF;ansx=ansy=ansdir=;flag=-;
for(register int i=,xx=bx+dx[],yy=by+dy[];i<;++i,xx=bx+dx[i],yy=by+dy[i])if(dis[xx][yy]<INF&&!mp[bx-dx[i]][by-dy[i]])
q.push(make_pair(make_pair(xx,yy),i^)),pus[xx][yy][i^]=,walk[xx][yy][i^]=dis[xx][yy],las[xx][yy][i^]=make_pair(make_pair(,),);
while(!q.empty()){
int x=q.front().first.first,y=q.front().first.second,dir=q.front().second;q.pop();
int pushx=pus[x][y][dir]+,walkx=walk[x][y][dir];
if(~flag&&pushx>flag)return;if(pus[x+dx[dir]][y+dy[dir]][dir]<pushx)continue;
int kx=x+*dx[dir],ky=y+*dy[dir];
if(kx==tx&&ky==ty){flag=pushx;if(MIN(answ,walkx))ansx=x,ansy=y,ansdir=dir;continue;}
find_way(x+dx[dir],y+dy[dir],kx,ky);
for(register int i=,xx=kx+dx[],yy=ky+dy[];i<;++i,xx=kx+dx[i],yy=ky+dy[i])if(dis[xx][yy]<INF&&!mp[kx-dx[i]][ky-dy[i]])
if(pus[xx][yy][i^]>=pushx&&walk[xx][yy][i^]>=walkx+dis[xx][yy]){
pus[xx][yy][i^]=pushx,walk[xx][yy][i^]=walkx+dis[xx][yy],las[xx][yy][i^]=make_pair(make_pair(x,y),dir);
if(!vis[xx][yy][i^])q.push(make_pair(make_pair(xx,yy),i^)),vis[xx][yy][i^]=;
}
}
}
char ans[];int len,T,ent;pii Pre[N][N];
inline void print_way(int fx,int fy,int lx,int ly,int bX,int bY){
if(fx==lx&&fy==ly)return;
mp[bX][bY]=;mst(dis,INF);dis[fx][fy]=,Pre[fx][fy]=make_pair(,);queue<pii> q;q.push(make_pair(fx,fy));
while(!q.empty()){
int x=q.front().first,y=q.front().second;q.pop();if(x==lx&&y==ly)break;
for(register int i=;i<;++i)if(!mp[x+dx[i]][y+dy[i]]&&dis[x+dx[i]][y+dy[i]]>dis[x][y]+)
dis[x+dx[i]][y+dy[i]]=dis[x][y]+,q.push(make_pair(x+dx[i],y+dy[i])),Pre[x+dx[i]][y+dy[i]]=make_pair(x,y);
}mp[bX][bY]=;int x=Pre[lx][ly].first,y=Pre[lx][ly].second;
while(x)ans[++len]=(x^lx?(x==lx-?'s':'n'):(y==ly-?'e':'w')),lx=x,ly=y,x=Pre[lx][ly].first,y=Pre[lx][ly].second;
}
inline void print(){
len=;while(ansx){
ans[++len]=d[ansdir];
int x=las[ansx][ansy][ansdir].first.first,y=las[ansx][ansy][ansdir].first.second,dir=las[ansx][ansy][ansdir].second;
if(x)print_way(x+dx[dir],y+dy[dir],ansx,ansy,x+(dx[dir]<<),y+(dy[dir]<<));else break;
ansx=x,ansy=y,ansdir=dir;
}
print_way(sx,sy,ansx,ansy,bx,by);
for(register int i=len;i;--i)printf("%c",ans[i]);puts("");puts("");
} int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
while(read(n),read(m),n&&m){
char s[];//if(ent)puts("");else ent=1;
for(register int i=;i<=n;++i){
scanf("%s",s+);mp[i][]=mp[i][m+]=;
for(register int j=;j<=m;++j)switch(s[j]){
case '#':mp[i][j]=;break;
case '.':mp[i][j]=;break;
case 'S':mp[i][j]=,sx=i,sy=j;break;
case 'T':mp[i][j]=,tx=i,ty=j;break;
case 'B':mp[i][j]=,bx=i,by=j;break;
}
}
for(register int j=;j<=m+;++j)mp[][j]=mp[n+][j]=;
start_pushing();printf("Maze #%d\n",++T);if(~flag)print();else printf("Impossible.\n\n");
}
return ;
}
poj1475 Pushing Boxes[双重BFS(毒瘤搜索题)]的更多相关文章
- 『Pushing Boxes 双重bfs』
Pushing Boxes Description Imagine you are standing inside a two-dimensional maze composed of square ...
- 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)
题目链接 http://poj.org/problem?id=1475 题意 推箱子游戏.输入迷宫.箱子的位置.人的位置.目标位置,求人是否能把箱子推到目标位置,若能则输出推的最少的路径,如果有多条步 ...
- POJ1475 Pushing Boxes(双搜索)
POJ1475 Pushing Boxes 推箱子,#表示墙,B表示箱子的起点,T表示箱子的目标位置,S表示人的起点 本题没有 Special Judge,多解时,先最小化箱子被推动的次数,再最小化 ...
- POJ1475 Pushing Boxes 华丽丽的双重BFS
woc累死了写了两个半小时...就是BFS?我太菜了... 刚开始以为让人预先跑一遍BFS,然后一会儿取两节加起来就好了,结果发现求出来的最短路(就是这个意思)会因箱子的移动而变化....我死了QWQ ...
- POJ1475(Pushing Boxes)--bbffss
题目在这里 题目一看完就忙着回忆童年了.推箱子的游戏. 假设只有一个箱子.游戏在一个R行C列的由单位格子组成的区域中进行,每一步, 你可以移动到相邻的四个格子中的一个,前提是那个格子是空的:或者,如果 ...
- POJ1475 Pushing Boxes(BFS套BFS)
描述 Imagine you are standing inside a two-dimensional maze composed of square cells which may or may ...
- poj1475 -- Pushing Boxes
这道题其实挺有趣 的,这让我想起小时候诺基亚手机上的推箱子游戏(虽然一点也不好玩) (英文不好-->) 题意翻译: 初始人(S),箱子(B),目的地(T)用人把箱子推到 T最小步数及其路径(满 ...
- Pushing Boxes(广度优先搜索)
题目传送门 首先说明我这个代码和lyd的有点不同:可能更加复杂 既然要求以箱子步数为第一关键字,人的步数为第二关键字,那么我们可以想先找到箱子的最短路径.但单单找到箱子的最短路肯定不行啊,因为有时候不 ...
随机推荐
- 19:ReverseNumber数字颠倒
题目描述 描述:输入一个整数,将这个整数以字符串的形式逆序输出 程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001 输入描述:输入一个int整数 输出描述:将这个整 ...
- 使用python处理实验数据-yechen_pro_20171231
整体思路 1.观察文档结构: - 工况之一 - 流量一28 - 测点位置=0 -测点纵断面深度-1 -该点数据Speedxxxxxxxx.txt -测点纵断面深度-2 -测点纵断面深度-3 -... ...
- Qt中的对象类型转换
char * 与 const char *的转换 char *ch1="hello11"; const char *ch2="hello22"; ch2 = c ...
- 二、Silverlight中使用MVVM(二)——提高
在第一篇文章中的示例中,我们已经简单的了解了应用MVVM模式的流程,我的本意是你已经了解了一点MVVM的概念,然后又没有一个较好的例子学习,可以跟着我一起学习MVVM模式,所以这个部分,都是没有理论知 ...
- 禁用android studio自身的ndk编译disable automatic ndk-build call
1,让studio不自动编译jni文件,而是我们手动通过ndk-build编译 打开工程下面的app文件夹, 找到build.gradle 添加如下: defaultConfig { ...
- C打印函数printf的一种实现原理简要分析
[0]README 0.1)本文旨在对 printf 的 某一种 实现 原理进行分析,做了解之用: 0.2) vsprintf 和 printf.c 的源码,参见 https://github.com ...
- phpstudy nginx下curl请求本地其他项目
curl 请求的时候 如果用post请求,传递参数为 数组的时候 header 头 会被设置为 multipart/form-data 如果是字符串 形式 header 头会被设置为applica ...
- 初探swift语言的学习笔记四-2(对上一节有些遗留进行处理)
作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/30314359 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...
- go test 上篇
前言 Go语言本身集成了轻量级的测试框架,由go test命令和testing包组成.包含单元测试和压力测试,是保证我们编写健壮Golang程序的有效工具. 演示环境 $ uname -a Darwi ...
- EasyNVR摄像机H5流媒体服务器在windows上批处理脚本自动以管理员权限运行
很多时候, 我们需要以管理员权限来运行批处理脚本, 比如操作 windows 服务. EasyNVR 中提供安装服务的批处理脚本, 运行这个bat文件, 自动将 EasyNVR 以 windows 服 ...