題目描述:
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 <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
}