走迷宮(廣度優先算法)


題目描述:

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
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM