这道题其实挺有趣 的,这让我想起小时候诺基亚手机上的推箱子游戏(虽然一点也不好玩)
(英文不好-->) 题意翻译:
初始人(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; }