迷宮問題(BFS)

給定一個大小爲N*M的迷宮,由通道('.')和牆壁('#')組成,其中通道S表示起點,通道G表示終點,每一步移動可以達到上下左右中不是牆壁的位置。試求出起點到終點的最小步數。(本題假定迷宮是有解的)(N,M<=100)

樣例輸入:
10 10
#S######.#
......#..#
.#.##.##.#
.#........
##.##.####
....#....#
########.#
....#.....
.####.###.
....#...G#

這道題目以及解法均來自《挑戰程序設計競賽(第2版)》第34頁-36頁;書中解法使用了真正的隊列,而我在這裏是用了數組模擬隊列,但是結果都是一樣的。

個人覺得這個例題很好地表現了廣度優先搜索是如何與隊列先進先出(FIFO)的思想聯繫起來的,通過不斷取得某個狀態後能夠達到的所有狀態並將其加入隊列, 並且由於隊列本身的特性先加入隊列的狀態總是先得到處理,這樣就達到了一個目的:總是先將需要轉移次數更少的狀態進行分析處理,換句話說就是總是取得了這個狀態的樹中更接近根部的節點,又或者是總是讓搜索樹的廣度得到儘可能增加。

在這個問題中,找到從起點到終點的最短路徑其實就是一個建立隊列的過程:

1.從起點開始,先將其加入隊列,設置距離爲0;

2.從隊列首端取出位置,將從這個位置能夠到達的位置加入隊列,並且讓這些位置的距離爲上一個位置的距離加上1;

3.循環2直到將終點添加到隊列中,這說明我們已經找到了路徑;

注意到在這個過程中,每次處理的位置所對應的距離是嚴格遞增的,因此一旦找到終點,當時的距離就是最短距離;

同樣基於這個原因,搜索可移動到的位置所使用的判斷條件中不僅僅是不碰牆壁、不超過邊界,還有一個就是沒有到達過,因爲如果已經到達了這個位置,這說明已經有更短的路徑到達這個位置,這次到達這個位置的路徑是更差的,不可能得到更好的最終解。

#include<iostream>
#include<cstdio>
using namespace std;
const int INF = 100000000;
char map[3000][3000];
int d[3000][3000];
int mov[4][2] = {1,0,-1,0,0,1,0,-1};
int n,m,sx,sy,gx,gy;
pair <int,int> que[1010];
int bfs()
{
    int frt = 0,til = 0;
    for(int i = 0;i < n; i++)
    {
        for(int j = 0;j < m; j++)
        {
            d[i][j] = INF;
        }
    }
    que[til].first = sx;
    que[til++].second = sy;
    d[sx][sy] = 0;
    while(frt != til)
    {
        int nx = que[frt].first;
        int ny = que[frt++].second;
        if(nx == gx && ny == gy)
            break;
        for(int i = 0;i < 4; i++)
        {
            int x = nx + mov[i][0];
            int y = ny + mov[i][1];
            if(x >= 0 && x < n && y >= 0 && y < m && map[x][y] != '#' && d[x][y] == INF)
            {
                que[til].first = x;
                que[til++].second = y;
                d[x][y] = d[nx][ny] + 1;
            }
        }
    }
    return d[gx][gy];
}
int main()
{
    scanf("%d %d",&n,&m);
    getchar();
    for(int i = 0;i < n; i++)
    {
        scanf("%s",map[i]);
        getchar();
        for(int j = 0;j < m; j++)
        {
            if(map[i][j] == 'S')
            {
                sx = i;
                sy = j;
                continue;
            }
            if(map[i][j] == 'G')
            {
                gx = i;
                gy = j;
            }
        }
    }
    int res = bfs();
    res != INF ? printf("%d",res) : printf("-1");
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章