题目链接Problem - 1254
前段时间,本萌新做了一个推箱子的问题。当时为了写这道题,还专门玩了几关推箱子,想了一天,终于在学长的帮助下,得出了一个平民解法。。。没错,纯bfs。。。
大体板子:
既然箱子到指定地点才算成功,那我们不妨就让箱子进行上下左右移动,看箱子到指定要走多少格。
重点一:去重
在这道题中,去重是个不能忽视的问题,总不能让人一直跑,但是如果像往常一样仅仅按照单个箱子的坐标去重,又会少考虑很多情况。“方向”是一个很重要的判断因素,我们可以开个bool三维版去判断是否重复(一个下标是x,一个下标是y,还有一个下标用0,1,2,3代表推的四个方向)。
重点二:人
箱子推的方向,都取决于人。例如箱子此时的坐标为(x,y),枚举到箱子向右推到(x,y+1),那此时人必须能够到达(x,y-1)才能实现这个功能。所以,就用到了第二个bfs来做判断,判断人能否到他因该到达的位置,如果不能,就跳过进行下一个枚举。
重点三:箱子被卡死
如果玩过推箱子的话,就直到,箱子的四个相邻的格子,倘若有两个(非像上下或左右这样的对应方向)及以上都是墙,那这个箱子就可以good game了,耶稣来了都救不了,我说的,因而这种情况也要进行判断并加以考虑。
代码如下:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<math.h>
#include<string.h>
#include<queue>
#include<stack>
typedef long long ll;
using namespace std;
ll n,m;
ll xz,yz,x2,y2,x3,y3;
int b[20][20];
bool c[20][20][5];
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
bool r[20][20];
struct we{
ll x,y;
ll bu;
ll renx;
ll reny;
};
bool ren(we yuan,we xian){
queue<we>zz;
memset(r,0,sizeof(r));
r[yuan.renx][yuan.reny]=1;
zz.push({yuan});
while(!zz.empty()){
we emm=zz.front();
zz.pop();
if(emm.renx==xian.renx&&emm.reny==xian.reny){
return 0;
}
for(int i=0;i<4;i++){
int xx=emm.renx+dx[i];
int yy=emm.reny+dy[i];
if(xx<1||xx>n||yy<1||yy>m||r[xx][yy]==1||b[xx][yy]==1||(xx==yuan.x&&yy==yuan.y))continue;
r[xx][yy]=1;
zz.push({emm.x,emm.y,0,xx,yy});
}
}
return 1;
}
int main(){
ll t;
cin>>t;
while(t--){
queue<we>hh;
cin>>n>>m;
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>b[i][j];
if(b[i][j]==4){
xz=i;
yz=j;
}
if(b[i][j]==2){
x2=i;
y2=j;
}
if(b[i][j]==3){
x3=i;
y3=j;
}
}
}
hh.push({x2,y2,0,xz,yz});
ll ans=-1;
while(!hh.empty()){
we now=hh.front();
if(now.x==x3&&now.y==y3){
ans=now.bu;
break;
}
hh.pop();
for(int i=0;i<4;i++){
int xx=now.x+dx[i];
int yy=now.y+dy[i];
int rx=now.x-dx[i];
int ry=now.y-dy[i];
if(rx<1||rx>n||ry<1||ry>m||b[rx][ry]==1)continue;
if(c[xx][yy][i]==1)continue;
if(xx<1||xx>n||yy<1||yy>m||b[xx][yy]==1)continue;
we will;
will.x=xx;
will.y=yy;
will.renx=rx;
will.reny=ry;
will.bu=now.bu+1;
if(ren(now,will))continue;
c[xx][yy][i]=1;
hh.push(will);
}
}
cout<<ans<<"\n";
}
}