走迷宫(广度优先算法)

题目描述:

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

需要注意的要点:

  1. 为多case
  2. 对走过的格子要设为“1”
  3. 起点和终点重合的情况

对广度优先遍历算法的理解

走迷宫用的广度优先遍历,用例子引入,可以理解为水的波纹,像周围荡开,但是不太能体现节点与节点间的关系,所以在这个基础上,我更想把其比作蜘蛛网,当有物体撞击蜘蛛网的时候,在物体撞击的位置(初始节点),这个撞击的力沿着与初始节点有连接的蛛丝传递到下一个结点,并重复此步骤,而且不会返回来。也就是在广度遍历时,会对节点周围相关联且未遍历的点先进行遍历,然后重复此步骤直至所有节点都被遍历。由于与一个节点相关联的节点有多个且不能同时进行遍历,我们可以用队列模拟这种“同时”的遍历。

具体例子:

  1. 对起点进行遍历,发现周围四个方向都要进行遍历

  2. 将四个方向的状态压入队列

  3. 遍历起点

  4. 起点遍历结束,遍历起点的第一个方向上的点,并将与其相关联的点压入队列为,设第一个方向相关联的点组成的集合为 T1,第二个为T2,如此类推。

    当前队列为:起点第二个方向,起点第三个方向,起点第四个方向,T1

  5. 循环4步骤直到队列状态为:

    ​ 起点第四个方向,T1,T2,T3

  6. 当起点第四个方向被遍历并从队列中弹出,此时,队列完成了对起点四个方向“同时”遍历的模拟。

代码(含注释)

#include <iostream>
#include <cstdio>
#include <malloc.h>
#include <queue>
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<m;i++)
        {
            scanf("%s",s[i]);       //每行迷宫
        }
        int num;
        scanf("%d",&num);       //传送门数量
        for(i=0;i<num;i++)
        {
            scanf("%d%d%d%d",&In[i][0],&In[i][1],&Out[i][0],&Out[i][1]);        //传送门入口坐标和出口坐标
        }
        scanf("%d%d%d%d",&sr,&sc,&er,&ec);      //起点和终点坐标

         node first;
         first.row=sr;
         first.col=sc;
         first.step=0;      //设置起点node

         queue <node> 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<num;i++)     //检测是不是传送门位置
             {
                 if(cur.row==In[i][0]&&cur.col==In[i][1])
                 {
                     node newnode;
                     newnode.row=Out[i][0];
                     newnode.col=Out[i][1];         //传送后的坐标
                     newnode.step=cur.step+1;       //步数+1
                     Q.push(newnode);       //推入该坐标
                     jump=1;        //传送门使用标志
                     break;

                 }
             }
             if(!jump)      //未使用传送门
             {

                 for(i=0;i<4;i++)       //四个方向
                 {
                     int k=0;
                     node now;
                     now.row=cur.row+d[i][0];
                     now.col=cur.col+d[i][1];
                     now.step=cur.step+1;       //步数+1
                     if(now.row<0||now.row>=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
}

posted @ 2019-06-02 02:00  Dozeer  阅读(5124)  评论(0编辑  收藏  举报
Live2D