题目描述:
Description
有一个N*M的格子迷宫,1代表该格子为墙,不能通过,0代表可以通过,另外,在迷宫中
有一些传送门,走到传送门的入口即会自动被传送到传送门的出口(一次传送算1步)。人在迷宫中可以尝试
上下左右四个方向移动。现在给定一个迷宫和所有传送门的出入口,以及起点和终点,
问最少多少步可以走出迷宫。如果不能走出迷宫输出“die”。
输入格式
该程序为多CASE,第1行为CASE的数量
每一个CASE,第1行为两个数N(行)和M(列)
然后N行每行M个数
之后是一个数W,为传送门的数量
之后每行一个传送门的入口坐标c1(行),r1(列)和出口坐标c2,r2
之后是起点坐标和终点坐标sc(行) sr(列) ec(行) er(列)
注:传送门出入口和起点坐标和终点坐标不会出现在墙的位置
所有数字不超过100
输出格式
如题
输入样例
2
4 3
011
011
110
110
1
1 0 2 2
0 0 3 2
2 2
01
10
0
0 0 1 1
输出样例
3
die
做题思路:
建立多个二维数组,分别保存地图、出入口、传送门出入口,并需要设置一个标志变量确定是否到达终点
可以利用广度优先遍历模拟走迷宫的状态,那就需要用一个结构体保存当前位置在地图中的坐标,离起点所走的步数。
在走迷宫的过程中,对为“1”的格子,不对其进行遍历;对为传送门入口坐标的格子,需要将目前状态调整为传送门出口位置的坐标,并使步数加1;对为终点的格子,置到达终点的标志变量,并结束该case
需要注意的要点:
- 为多case
- 对走过的格子要设为“1”
- 起点和终点重合的情况
对广度优先遍历算法的理解
走迷宫用的广度优先遍历,用例子引入,可以理解为水的波纹,像周围荡开,但是不太能体现节点与节点间的关系,所以在这个基础上,我更想把其比作蜘蛛网,当有物体撞击蜘蛛网的时候,在物体撞击的位置(初始节点),这个撞击的力沿着与初始节点有连接的蛛丝传递到下一个结点,并重复此步骤,而且不会返回来。也就是在广度遍历时,会对节点周围相关联且未遍历的点先进行遍历,然后重复此步骤直至所有节点都被遍历。由于与一个节点相关联的节点有多个且不能同时进行遍历,我们可以用队列模拟这种“同时”的遍历。
具体例子:
对起点进行遍历,发现周围四个方向都要进行遍历
将四个方向的状态压入队列
遍历起点
起点遍历结束,遍历起点的第一个方向上的点,并将与其相关联的点压入队列为,设第一个方向相关联的点组成的集合为 T1,第二个为T2,如此类推。
当前队列为:起点第二个方向,起点第三个方向,起点第四个方向,T1
循环4步骤直到队列状态为:
起点第四个方向,T1,T2,T3
当起点第四个方向被遍历并从队列中弹出,此时,队列完成了对起点四个方向“同时”遍历的模拟。
代码(含注释)
#include
#include
#include
#include
using namespace std;
int d[4][2]={{-1,0},{0,1},{1,0},{0,-1}}; //四个方向
char s[110][110]; //地图大小
int sr,sc; //初始地点
int er,ec; //目标地点
int In[110][2],Out[110][2]; //传送门入口和出口坐标
typedef struct{
int row;
int col; //位置
int step; //步数
}node; //每次走的记录
int main()
{
int k;
scanf("%d",&k); //多case
while(k--)
{
int m,n,flag=0,jump=0;
scanf("%d%d",&m,&n); //行列数
int i;
for(i=0;i Q;
Q.push(first);
while(!Q.empty())
{
node cur;
cur=Q.front();
Q.pop();
jump=0;
if(cur.row==er&&cur.col==ec) //是否是终点
{
printf("%d\n",cur.step);
flag=1; //已到达终点标志
break;
}
for(i=0;i=m||now.col<0||now.col>=n) continue; //边界检测
if(s[now.row][now.col]=='0')
{
s[now.row][now.col]='1'; //走过的标志位
Q.push(now);
}
}
}
}//while
if(!flag) //flag未设置成终点标志,die
{
printf("die\n");
}
}//while
}