搜索-BFS|【POJ1475】Pushing Boxes-A*(或BFS())

测试地址:Pushing Boxes
题目大意:给定一个r*c的矩形地图,里面有一些石头,有石头的地方不能走,你一开始在S点,要将地图中的一个箱子B推到目标点T(玩过推箱子小游戏的同学应该很容易理解,没玩过的话我在这里解释一下,就是当你要往一个方向移动时,箱子正好在你要到达的地方,此时你和你的箱子都要往那个方向移动一步),箱子也不能被推到有石头的地方,求出一个表示路线的字符串,其中小写字母表示普通的移动,大写字母表示推着箱子时的移动,字母表示方向,要求推箱子的次数最少,如果有多解,输出总移动次数最少的,如果还是有多解,任意输出一个。如果不可能推到,输出“Impossible.”。
做法:这道题目看上去比较复杂,我们来梳理一下。首先要确定搜索时要记录的状态,这个很容易能想到:人的位置和箱子的位置。由于题目中要求的最优解,我们还要附加两个值pushes和walk,表示推动箱子的移动数和平常的移动数,pushes优先级比walk高,然后和前面已经搜出的状态做双关键字比较,如果比以前的状态好,就可以加入优先队列中,优先队列的排序规则也是这个规则。输出路线的话,只要记录一个状态的“父节点”,即拓展到该节点并使该节点状态最优的点,如果箱子的位置到达了T,就从这个状态开始反着搜,判断行走的方向即可。怎么判断是否推动了箱子?只要查看箱子的坐标是否移动即可。还有一个地方坑了我一把,就是存储路线的字符数组一定要开大,因为一个点不一定只走一遍或两遍,所以无法轻易判断路线的长度,所以内存足够的情况下,只能开大一点保险。
(这道题的确是好题...学习A*的同学一定要做一做)
(听说还有双BFS的方法?有待学习)
以下是本人代码:

#include #include #include #include #include #include using namespace std; int r,c,move[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; int fa[30][30][30][30][4],h[30][30][30][30][2],t=0; char a[30][30]; bool flag; struct node {int x,y; } S,B,T; struct state { node s,b; int pushes,walk; bool operator < (state a) const { if (pushes!=a.pushes) return a.pushes【搜索-BFS|【POJ1475】Pushing Boxes-A*(或BFS())】=1&&x<=r&&y>=1&&y<=c&&a[x][y]!='#'; }void outputpath(int sx,int sy,int g) { char r[10000]; flag=1; int x1=sx,y1=sy,x2=T.x,y2=T.y,j=g; while(j>0) { int fx1,fx2,fy1,fy2; char tmp='a'; fx1=fa[x1][y1][x2][y2][0]; fy1=fa[x1][y1][x2][y2][1]; fx2=fa[x1][y1][x2][y2][2]; fy2=fa[x1][y1][x2][y2][3]; if (fx2!=x2||fy2!=y2) tmp='A'; if (x1-fx1==-1) r[j]='N'-'A'+tmp; if (x1-fx1==1) r[j]='S'-'A'+tmp; if (y1-fy1==-1) r[j]='W'-'A'+tmp; if (y1-fy1==1) r[j]='E'-'A'+tmp; j--; x1=fx1,y1=fy1,x2=fx2,y2=fy2; } for(int i=1; i<=g; i++) printf("%c",r[i]); }void AStar() { memset(fa,0,sizeof(fa)); memset(h,0x7f,sizeof(h)); priority_queue Q; state now,next; now.s=S,now.b=B; now.pushes=now.walk=0; Q.push(now); while(!Q.empty()) { now=Q.top(); Q.pop(); if (now.b.x==T.x&&now.b.y==T.y) {outputpath(now.s.x,now.s.y,now.pushes+now.walk); break; } for(int i=0; i<=3; i++) if (can(now.s.x+move[i][0],now.s.y+move[i][1])) { next.s.x=now.s.x+move[i][0]; next.s.y=now.s.y+move[i][1]; if (now.b.x==now.s.x+move[i][0]&&now.b.y==now.s.y+move[i][1]) { if (!can(now.b.x+move[i][0],now.b.y+move[i][1])) continue; next.b.x=now.b.x+move[i][0]; next.b.y=now.b.y+move[i][1]; next.pushes=now.pushes+1; next.walk=now.walk; } else { next.b.x=now.b.x; next.b.y=now.b.y; next.walk=now.walk+1; next.pushes=now.pushes; } if (best(next)) { fa[next.s.x][next.s.y][next.b.x][next.b.y][0]=now.s.x; fa[next.s.x][next.s.y][next.b.x][next.b.y][1]=now.s.y; fa[next.s.x][next.s.y][next.b.x][next.b.y][2]=now.b.x; fa[next.s.x][next.s.y][next.b.x][next.b.y][3]=now.b.y; setbest(next); Q.push(next); } } } }int main() { while(scanf("%d%d",&r,&c)&&r&&c) { t++; for(int i=1; i<=r; i++) { char s[30]; scanf("%s",s); for(int j=1; j<=c; j++) { a[i][j]=s[j-1]; if (s[j-1]=='S') S.x=i,S.y=j; if (s[j-1]=='B') B.x=i,B.y=j; if (s[j-1]=='T') T.x=i,T.y=j; } } printf("Maze #%d\n",t); flag=0; AStar(); if (!flag) printf("Impossible."); printf("\n\n"); }return 0; }



    推荐阅读