POJ 3984 迷宮問題 詳細講解註解

POJ 3984ios

題目

Description

定義一個二維數組:編程

int maze[5][5] = {

	0, 1, 0, 0, 0,

	0, 1, 0, 1, 0,

	0, 0, 0, 0, 0,

	0, 1, 1, 1, 0,

	0, 0, 0, 1, 0,

};

它表示一個迷宮,其中的 1 表示牆壁,0 表示能夠走的路,只能橫着走或豎着走,不能斜着走,要求編程序找出從左上角到右下角的最短路線。數組

Input

一個5 × 5的二維數組,表示一個迷宮。數據保證有惟一解。優化

Output

左上角到右下角的最短路徑,格式如樣例所示。spa

Sample Input

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0code

Sample Output

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)blog

解題思路

這題是迷宮求最短路徑問題,因爲迷宮的邊權都爲 1, 因此優先使用寬度優先搜索 BFS來作隊列

當BFS找到終點時,說明找到了一條最短路徑,因此要有一個記錄當前路徑的方法ip

*** 判斷遍歷到終點的方法 ***
if ( tx == 4 && ty == 4 ) return tt - 1;

這裏的作法是開一個struct數組來當隊列,裏面包含了當前遍歷到的點x, y與當前點的父節點位置(由父節點擴展到點x,y)內存

找到終點時,咱們從終點開始看,找到它父節點在隊列中的位置,記錄它信息(x, y),再把這個父節點當成起始點,再次回溯它的父節點...

將父節點內存儲的座標逐一壓入堆棧中,當回溯的父節點位置爲-1時,中止回溯,開始將堆棧中的內容所有彈出打印。

註釋代碼

#include <iostream>
#include <stack>
#include <cstdio>

using namespace std;

const int N = 30;

typedef pair<int, int> PII;

/* 堆棧 stack 的元素爲 pair ,以 .first 和 .second 的方式訪問 pair 內的兩個元素 */

stack<PII> stck; 

struct stu {
    int x;
    int y;
    int p;       /* p 即爲 當前點的父節點在隊列 q 中的下標 */
} q[N];          /* q 即爲 隊列, 使用數組來模擬隊列 */

/* 存放地圖數據 */
int a[10][10];   

/* 表示 x, y 這個點是否進入過隊列,每一個點最多隻進入隊列一次(優化) */
bool st[N][N];

/* 下一個點的方向 */
int ne[2][4] = { {0, -1, 0, 1 }, {1, 0, -1, 0} };  

/* bfs 返回終點在隊列中的位置 */
int bfs ( void )
{
    int hh = 0, tt = 0;         // 隊頭hh  隊尾tt

    q[tt++] = { 0, 0, -1 };     // 添加隊頭元素,父節點設置爲-1,表示這是隊頭

    st[0][0] = true;            // (0, 0)點已添加進隊列

    while ( tt > hh )           // 隊列不爲空則循環
    {
        struct stu t = q[hh++]; // 取隊頭元素     
        
        /* 枚舉四個方向 */
        for ( int i = 0; i < 4; i++ )  
        {

            int tx = t.x + ne[0][i];
            int ty = t.y + ne[1][i];

            /*
                三大判斷條件
                一、tx,ty在邊界內
                二、當前點的值爲 0
                三、當前點未被加入過隊列
            */
            if ( tx >= 0 && ty >= 0 && tx <= 4 && ty <= 4 && !st[tx][ty] && a[tx][ty] == 0 )
            {
                st[tx][ty] = true;              
                q[tt++] = {tx, ty, hh - 1};  // 當前隊首 - 1即爲它的父節點
            }
            if ( tx == 4 && ty == 4 ) return tt - 1; 
        }
    }
}

int main ( void )
{
    /* 將輸入數據存入地圖中 */
    for ( int i = 0; i < 5; i++ )
        for ( int j = 0; j < 5; j++ )
            cin >> a[i][j];

    int t = bfs();  // 接收BFS的返回值,此時 t 表明終點在隊列 q 中位置
    
    /* 
        i = t

        只要 i != -1,意思就是沒有遍歷到頭節點 就一直循環,

        每次循環後更新 i = q[i].p 意思是讓 i 變爲當前 i 所表示點的父節點的位置

        每次循環將當前的座標壓入堆棧
    */
    for ( int i = t; i != -1; i = q[i].p )
        stck.push ( {q[i].x, q[i].y} );
    
    /* 
        只要堆棧不爲空,就彈出棧頂元素並輸出
    */
    while ( !stck.empty() )
    {
        PII i = stck.top();
        stck.pop();

        printf ( "(%d, %d)\n", i.first, i.second );
    }

    return 0;
}

輸入 / 輸出:

若是有寫的很差的地方,或者有哪裏尚未理解的地方,請積極留言

相關文章
相關標籤/搜索