Pushing Boxes(广度优先搜索)

题目传送门

首先说明我这个代码和lyd的有点不同:可能更加复杂

 既然要求以箱子步数为第一关键字,人的步数为第二关键字,那么我们可以想先找到箱子的最短路径。但单单找到箱子的最短路肯定不行啊,因为有时候不能被推动,怎样确定一条既满足最短又满足可行的箱子路径呢,其实这就是一种有限制的BFS

 对于箱子:

  设现在的位置为x,y,扩展方向为dx,dy,将要到达的下一个位置为x+dx,y+dy

 check它是否可行:

1.不越界。

2.之前没有走过。

3.不能走到“#”上。

4.人能够从当前站立的位置到达(x-dx,y-dy)。

诶,对了,第4个条件实际上就是对于人的bfs。


 

  因此,这就是一个双重bfs。(数据范围r,c<=20可行!)

  那么对于人的bfs,有什么限制条件:当然最重要的不能走到箱子现在的位置(x,y)上

  还有记录路径,每次回溯和逆推。

  嗯,具体细节看代码吧(不想打字了)

 

//Pushing Boxes -POJ1475 
//最长代码 祭 AC  329ms
//开始没有数组清零WA
//然后数组开大了,TLE 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
#define de system("pause");
#define re register int
using namespace std;
int r,c,ans,ansx,ansy;
char s[50][50];
int per[5],box[5];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
char ren[]={'n','s','w','e'};
char xiang[]={'N','S','W','E'};
bool bz[30][30],flag[30][30];
struct node{
    int x,y,step;
    int man[3];
    node(int xx,int yy,int stepp,int mx,int my)
    {
        x=xx,y=yy,step=stepp;
        man[1]=mx,man[2]=my;
    }
};
struct node2{
    int x,y;
    node2(int xx,int yy)
    {
        x=xx;
        y=yy;
    }
};
queue<node> q;
queue<node2> p;
struct hp{
    int px,py,d;
    int cnt;
    int path[500];
}fix[30][30],walk[30][30];
//fix主要记录箱子的路径,walk主要记录人的路径。 inline
bool bfs(int bx,int by,int aimx,int aimy,int nowx,int nowy) { memset(flag,0,sizeof flag); memset(walk,0,sizeof walk); while(p.size()) p.pop(); p.push(node2(nowx,nowy)); if(nowx==aimx&&nowy==aimy) return 1; flag[nowx][nowy]=1; while(!p.empty()) { node2 now=p.front(); int x=now.x,y=now.y; p.pop(); for(re i=0;i<=3;++i) { int cx=x+dx[i],cy=y+dy[i]; if(cx<1||cx>r||cy<1||cy>c)continue; if(flag[cx][cy])continue; if(s[cx][cy]=='#')continue; if(cx==bx&&cy==by)continue; p.push(node2(cx,cy)); flag[cx][cy]=1; walk[cx][cy].px=x; walk[cx][cy].py=y; walk[cx][cy].d=i; if(cx==aimx&&cy==aimy) { return 1; } } } return 0; } inline bool check(int x,int t1,int y,int t2,int standx,int standy) { if(x+t1<1||x+t1>r||y+t2<1||y+t2>c)return 0; if(bz[x+t1][y+t2]) return 0; if(s[x+t1][y+t2]=='#')return 0; if(bfs(x,y,x-t1,y-t2,standx,standy))//如果人能够移动 { int tx=x-t1,ty=y-t2;//从目标回溯到初位置 while(tx!=standx||ty!=standy) { hp temp=walk[tx][ty]; fix[x+t1][y+t2].path[++fix[x+t1][y+t2].cnt]=walk[tx][ty].d; tx=temp.px; ty=temp.py; }//在这里顺便就把这一次转移路径记录下来 return 1; } return 0; } inline void Bfs() { while(!q.empty()) { node now=q.front(); int x=now.x,y=now.y,step=now.step; int man_x=now.man[1],man_y=now.man[2]; q.pop(); for(re i=0;i<=3;++i) { int cx=x+dx[i],cy=y+dy[i]; if(check(x,dx[i],y,dy[i],man_x,man_y)) { q.push(node(cx,cy,step+1,x,y)); bz[cx][cy]=1; fix[cx][cy].px=x,fix[cx][cy].py=y; fix[cx][cy].d=i; if(s[cx][cy]=='T') { if(step+1<ans) { ans=step+1; ansx=cx,ansy=cy; } } } } } } char shuchu[600]; int rt=0; inline void print() { int num=0; int prx=ansx; int pry=ansy; int tt=0; while((prx!=box[1])||(pry!=box[2])) { hp ne=fix[prx][pry]; shuchu[++num]=xiang[ne.d]; for(re i=1;i<=ne.cnt;++i) { shuchu[++num]=ren[ne.path[i]]; } prx=ne.px; pry=ne.py; } printf("Maze #%d\n",++rt); for(re i=num;i>=1;--i) cout<<shuchu[i]; puts(""); } int main() { while(1) { while(q.size())q.pop(); memset(bz,0,sizeof bz); // memset(shuchu,0,sizeof shuchu); memset(fix,0,sizeof fix); // memset(walk,0,sizeof walk); ans=1e6; scanf("%d%d",&r,&c); if(r==0&&c==0)break; for(re i=1;i<=r;++i){ scanf("%s",s[i]+1); for(re j=1;j<=c;++j){ if(s[i][j]=='B')box[1]=i,box[2]=j,bz[i][j]=1; if(s[i][j]=='S')per[1]=i,per[2]=j; } } q.push(node(box[1],box[2],0,per[1],per[2])); Bfs(); if(ans==1e6) { printf("Maze #%d\n",++rt); puts("Impossible."); } else print(); puts(""); } return 0; }

Add/ 

1.关于POJ的special judge可能有点毒瘤,所以建议按照'N','S','W','E'的方向进行搜索。

2.数组不要开大了。

3.输出两个换行......

posted @ 2019-03-12 17:28  南柯一场  阅读(339)  评论(0编辑  收藏  举报