题解 UVA589 【Pushing Boxes】

Boeing737_MAX_8

2019-07-16 10:41:35

Solution

``` 20191013修改:个人博客网址变更 ``` **欢迎前往[我的博客查看](https://officerbonin.home.blog/2019/07/16/uva589/)** 本题拿到来看,首先dfs在20*20的情况下是非常吃紧的,况且我们有两个移动物体:人与箱子。 所以首先先否定DFS(A*说不定行但反正我写不出来) 随后,这种走迷宫问题往BFS想。 仅仅是箱子移动,写BFS没有什么难度,于是要考虑人。 人推,推箱子,那么人必须得到**推的方向对面**,也就是我把**箱子往上推**,**人**得**在下面**。那么把人去推箱子要过去的位置暂时**称为人的目标位置**。 所以,如果推箱子到tarboxx,tarboxy,nx、ny为方向数组,人的目标位置就可以这么表示: ``` tarboxx=boxnowx+nx[i]; tarboxy=boxnowy+ny[i]; tarmanx=boxnowx+(-nx[i]); tarmany=boxnowy+(-ny[i]); ``` 所以我们还算**人过不过得去、人怎么过去**。这个时候只有再套一个BFS。专门计算人的路径。 这道题就简单明了了: 第一个(外层BFS)每到一个状态,对**四个方向移动**都进行枚举和判断(人能否走过去)。 此外,算人到目标位置的BFS应该判重。 **推箱子的BFS也应该判重**,定义vis[x][y][i]=1为:箱子**从i方向**去过(x,y)的位置。为啥这么定义呢?想想,箱子**并不是不能走重复路径**,而且**有时候必须走重复路径**,但是**没有必要来回三趟**或以上。 下面参考代码,~~有点长~~但是~~我认为比较好懂~~ 注意**多组数据的初始化**,还有**不加vis超时**。。。 ```cpp using namespace std; int n,m; struct node { int nowboxx,nowboxy; int nowmanx,nowmany; string ans; }; struct node2 { int xx, yy; string ways; }; bool isw[25][25]; int nx[6]= {0,-1,1,0,0}; int ny[6]= {0,0,0,-1,1}; int wayofvis[25][25][5]; char waysignz[6]=" nswe"; char waysignt[6]=" NSWE"; bool fpan; int mapf[25][25]; inline string bfspan(int nowboxx,int nowboxy,int stxx,int styy,int enxx,int enyy) { queue<node2>bfsq2; node2 p; memset(isw,0,sizeof isw); bfsq2.push({stxx,styy,""}); isw[stxx][styy]=1; int nowx,nowy,tarx,tary,nowcnt; string waynow; while(!bfsq2.empty()) { p=bfsq2.front(),bfsq2.pop(); nowx=p.xx,nowy=p.yy,waynow=p.ways; if(nowx==enxx&&nowy==enyy) { fpan=1; return waynow; } for(int i = 1; i <= 4; i++) { tarx=nowx+nx[i],tary=nowy+ny[i]; if(!mapf[tarx][tary]||isw[tarx][tary]||tarx==nowboxx&&tary==nowboxy|| (tarx>n||tarx<1||tary>m||tary<1) ) continue; isw[tarx][tary]=1; bfsq2.push({tarx,tary,waynow+waysignz[i]}); } } fpan=0; return ""; } int stboxx,stboxy,stmanx,stmany,enx,eny; string ans,anspr; void bfs() { queue<node>bfsq; node p; bfsq.push({stboxx,stboxy,stmanx,stmany,""}); int boxnowx,boxnowy,mannowx,mannowy; int tarboxx,tarboxy,tarmanx,tarmany; int nowcnt,nowmanride; string ansp; char way; while(!bfsq.empty()) { p=bfsq.front(); bfsq.pop(); boxnowx=p.nowboxx,boxnowy=p.nowboxy; mannowx=p.nowmanx,mannowy=p.nowmany; ansp=p.ans; if(boxnowx==enx&&boxnowy==eny) { printf("%s\n",ansp.c_str()); return; } for(int i = 1; i <= 4; i++) { tarboxx=boxnowx+nx[i]; tarboxy=boxnowy+ny[i]; if(!mapf[tarboxx][tarboxy]) continue; tarmanx=boxnowx+(-nx[i]); tarmany=boxnowy+(-ny[i]); if(!mapf[tarmanx][tarmany]||tarmanx>n||tarmanx<1||tarmany>m||tarmany<1||tarboxx>n||tarboxx<1||tarboxy>m||tarboxy<1) continue; if(mannowx==tarmanx&&mannowy==tarmany&&!wayofvis[tarboxx][tarboxy][i]) { bfsq.push({tarboxx,tarboxy,boxnowx,boxnowy,ansp+waysignt[i]}); wayofvis[tarboxx][tarboxy][i]=1; } else { anspr=bfspan(boxnowx,boxnowy,mannowx,mannowy,tarmanx,tarmany); if(fpan&&!wayofvis[tarboxx][tarboxy][i]) { bfsq.push({tarboxx,tarboxy,boxnowx,boxnowy,ansp+anspr+waysignt[i]}); wayofvis[tarboxx][tarboxy][i]=1; } } } } printf("Impossible.\n"); } int main() { while(~scanf("%d%d",&n,&m)&&(n+m)) { memset(wayofvis,0,sizeof wayofvis); char x; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { cin>>x; if(x=='#') mapf[i][j]=0; else mapf[i][j]=1; if(x=='B') stboxx=i,stboxy=j; else if(x=='S') stmanx=i,stmany=j; else if(x=='T') enx=i,eny=j; } } bfs(); } } ```