首先说明我这个代码和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.输出两个换行......