地址

很重要的搜索题。★★★


吐槽:算是写过的一道码量比较大的搜索题了,细节多,还比较毒瘤。虽然是一遍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(毒瘤搜索题)]的更多相关文章

  1. 『Pushing Boxes 双重bfs』

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

  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(双搜索)

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

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

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

  6. POJ1475(Pushing Boxes)--bbffss

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

  7. POJ1475 Pushing Boxes(BFS套BFS)

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

  8. poj1475 -- Pushing Boxes

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

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

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

随机推荐

  1. WikiCFP--A Wiki for Calls For Papers

    WikiCFP--A Wiki for Calls For Papers ---->www.wikicfp.com/cfp/

  2. 创业神人&当时钢铁侠:Elon Musk

    Steve Jobs的光环已经随着他的离去而淡褪,短期内,世上恐怕再难有人像他这样惊世骇俗般的改变了世界.但是如果你了解到一个人,一个来自南非年仅40岁的企业家,在短短的20年里,在全世界最酷的三个领 ...

  3. servletResponse 实用的页面跳转技术和定时刷新技术

    package response; import java.io.IOException;import java.util.Random; import javax.servlet.ServletEx ...

  4. u-boot-2014.04分析

    本文档以smdk2410为例初步分析了u-boot-2014.04的配置.启动流程.代码重定向.内存分布. u-boot-2014.04这个版本的uboot从Linux内核中借鉴了很多东西,比如编译u ...

  5. ASP.NET MVC路径引用总结

    1.关于路径: (1)绝对路径 包含站点路径的路径:<a href=”http://www.baidu.com/about.jpg”>百度</a> 站点改变路径失效: (2)相 ...

  6. MyBatis做动态模糊查询时,like后面要不要加单引号??

    做项目遇到了个奇怪的问题,项目里面要对商品.账户.进行分别的多条件查询,于是我就采用动态多条件分页查询,起初在做账户部分的时候Mybatis是这样写的 <!-- 动态多条件分页查询 --> ...

  7. Python学习总结之五 -- 入门函数式编程

    函数式编程 最近对Python的学习有些怠慢,最近的学习态度和学习效率确实很不好,目前这种病况正在好转. 今天,我把之前学过的Python中函数式编程简单总结一下,分享给大家,也欢迎并感谢大家提出意见 ...

  8. BZOJ 1002 FJOI2007 轮状病毒 递推+高精度

    题目大意:轮状病毒基定义如图.求有多少n轮状病毒 这个递推实在是不会--所以我选择了打表找规律 首先执行下面程序 #include<cstdio> #include<cstring& ...

  9. Altium Designer 敷铜间距设置,真实有效

    在任一PCB视图时,点击设计->规则,弹出规则设置对话框,如下图 找到Clearance,如下图, 使用右键单击,选择 新规则,如下图 在新规则上单击,在右侧 where  the first ...

  10. MySQL重置root用户密码的方法【亲测可用】

    1. 报错截图 2.当确认已经忘记MySQL密码,则可以通过以下方案重置root用户密码.双击打开C:\Program Files\MySQL\MySQL Server 5.1\my.ini文件,如下 ...