1
5 54
_____________________________________________________________________________________
思路:这道题就是我们小时候经常玩的推箱子游戏。特别注意:
1.每次 广搜走一步,都必须保存改变后的地图,并将状态压入栈中。
2.判重应该用三维数组,表示从该位置出发,四个方向都走过。
3.如果能推动箱子,那么人的位置和箱子的位置应该在地图中更新:
具体做法是:(1)先把人原来所在的位置 置0,(2)然后人到达推动箱子之前 箱子的位置。
(3)箱子被推动到其位置上。
下面看一个具体的测试用例:这是为什么要保存人的位置的原因。
1
5 6
0 0 1 0 0 0
4 2 0 0 0 0
0 0 1 0 1 1
0 0 1 0 1 1
0 0 1 3 1 1
1 2 3 4 5 6 7
箱子被推动的过程:右->右->右->左->下->下->下
#include
#include
#include
#include
#include
using namespace std;
#define INF 1<<30
int ma[8][8],vis[8][8][4];
int m,n;
struct point{
int mmap[8][8];
int x,y;//存储盒子所在的位置
int step;
bool operator==(const point&b)const{
if(this->x==b.x&&this->y==b.y)
return 1;
else
return 0;
}
bool check()
{
if(x>0&&x<=m&&y>0&&y<=n)
return 1;
else
return 0;
}
}s,per;//s为初始状态图
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//右 左 下 上
bool perReach(point bnow,point dest)//搜索人是否能到达指定位置
{
//如果先找到这个人的起始位置
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(bnow.mmap[i][j]==4)
{
per.x=i;per.y=j;break;
}
//起始位置符合要求
if(per==dest)return 1;
int vist[8][8];
memset(vist,0,sizeof(vist));
vist[per.x][per.y]=1;
point fat,now;
queueQ;
Q.push(per);//加入人的起始点
while(!Q.empty())
{
fat=Q.front();
Q.pop();
for(int i=0;i<4;i++)
{
now.x=fat.x+dir[i][0];
now.y=fat.y+dir[i][1];
// 目标点不是墙也不是箱子
if(now.check()&&!vist[now.x][now.y]&&bnow.mmap[now.x][now.y]!=1&&bnow.mmap[now.x][now.y]!=2)
{
if(now==dest)
return 1;
Q.push(now);
vist[now.x][now.y]=1;
}
}
}
return 0;
}
int bfs()
{
point fat,Perdest,bnow;
memset(vis,0,sizeof(vis));
queueQ;
Q.push(s);
while(!Q.empty())
{
fat=Q.front();
Q.pop();
// printf("盒子移动:%d %d 步数:%d\n",fat.x,fat.y,fat.step);
for(int i=0;i<4;i++)
{
//box所到的地方
bnow=fat;初始化盒子的位置及状态图
/**
☆ 1.这里不能写到for循环外面,因为每次地图都得清零
*/
bnow.x+=dir[i][0];
bnow.y+=dir[i][1];
bnow.step++;
//盒子要到达的地方在图内,并且没从这个方向 去过要到达的地方
if(bnow.check()&&!vis[bnow.x][bnow.y][i]&&ma[bnow.x][bnow.y]!=1)
{
//人所要到达的地方
Perdest.x=fat.x-dir[i][0];
Perdest.y=fat.y-dir[i][1];
人要到达的地方在图内,并且要到达的地方不为墙壁
if(Perdest.check()&&ma[Perdest.x][Perdest.y]!=1&&perReach(bnow,Perdest))
{
//能将盒子推到终点
if(ma[bnow.x][bnow.y]==3)
{
return bnow.step;
}
//更新地图
//更新人的原来的位置为0 当前人应该在原先box位置
bnow.mmap[per.x][per.y]=0;bnow.mmap[fat.x][fat.y]=4;
//更新盒子现在应该在的位置为2
bnow.mmap[bnow.x][bnow.y]=2;
/**
☆ 2.这里需要特别注意,更新的顺序
*/
Q.push(bnow);
vis[bnow.x][bnow.y][i]=1;
}
}
}
}
return -1;
}
int main()
{
int T,i,j;
cin>>T;
while(T--)
{
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&ma[i][j]);
//找到盒子所在的位置
s.mmap[i][j]=ma[i][j];
if(ma[i][j]==2)
{
s.x=i;
s.y=j;
s.step=0;
}
}
printf("%d\n",bfs());
}
return 0;
}
/**
special judge
1
5 6
0 0 1 0 0 0
4 2 0 0 0 0
0 0 1 0 1 1
0 0 1 0 1 1
0 0 1 3 1 1
should output 7
1
5 6
0 0 1 0 0 0
0 2 0 0 0 0
0 0 1 0 1 1
0 0 1 4 1 1
0 0 1 3 1 1
should output -1
*/