BFS 典型的迷宮問題


這個是BFS搜索的典型問題,好好整理一下:

    給定一個迷宮,入口為左上角,出口為右下角,問是否有路徑從入口到出口,若有則輸出一條這樣的路徑。注意移動可以從上、下、左、右、上左、上右、下左、下右八個方向進行。迷宮輸入0表示可走,輸入1表示牆。易得可以用1將迷宮圍起來避免邊界問題。本題采用BFS算法給出解。注意,利用BFS算法給出的路徑必然是一條最短路徑。

input:

1

6 8

0 1 1 1 0 1 1 1

1 0 1 0 1 0 1 0

0 1 0 0 1 1 1 1

0 1 1 1 0 0 1 1

1 0 0 1 1 0 0 0

0 1 1 0 0 1 1 0

output:

YES

(1,1) (2,2) (3,3) (3,4) (4,5) (4,6) (5,7) (6,8)

    基本思路:

    采用BFS的思路,每個位置相當於一個結點,用BFS進行廣度搜索,相當於往外一環一環擴散的感覺,最后看能否達到出口的位置。

    實現以及技巧:

    1.基本的數據結構:相比對於一棵樹的BFS來說,這里的BFS中的Node是一個坐標,因此要自定義好結點,typedef struct Node{int x; int y;}Node;BFS里面要用到隊列,對基本的隊列的庫函數的聲明和使用要熟悉,Q.size() Q.push(Node) Q.front() 以及Q.pop()

    2.關於path的問題:由於要存儲路徑信息,這里的path是一個二維的指針數組,注意這種聲明以及初始化的方式:聲明Node **path;初始化:

     path=new Node*[MAXL];

     for(i=0;i<=MAXL;i++)

     {path[i]=new Node[MAXH];}

    應該還有其他的表述方式,總之要會用一個,這里涉及到二維時候的指針還是挺麻煩的。

    3.還要注意每次path的更新點的選擇問題,在每次元素入隊的時候,比如當前元素為now,檢查它周圍的8個點,讓沒有牆的點入隊,比如一個沒有牆的點是temp就在這個位置上更新,path[temp.x][temp.y]=now。

    4.path輸出的問題也很重要,這個最好就記下來,就是遞歸輸出,比較典型,具體看代碼的outputpath函數。

    5.考慮向周圍移動的時候:向周圍的8個點移動的時候可以先設置好一個二維數組:

    Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}};

    之后一個循環,把對應的x y值加上去就好,這樣比較省事。注意結構體賦初值的時候也可以用這種小括號的形式:Node start={1,1};

    6.還有一點容易忽略,想周圍移動的時候,已經探測過的點要做個標記,比如標記成-1或者類似的,這樣就不會繞回去了,否則有可能形成一個環。

    7.還有其他的技巧,就是在地圖初始化的時候,在周圍加上一圈的圍牆,這樣在具體BFS的時候就不用再考慮邊界的問題了。

具體代碼如下:

//http://blog.csdn.net/that163/article/details/8069764
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define MAXH 20
#define MAXL 20
using namespace std;

typedef struct Node{
    int x;
    int y;
}Node;

//記錄地圖信息
int maze[MAXH][MAXL];
//記錄路徑信息
//Node*path[MAXH][MAXL];
Node **path;
Node move[8]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{-1,1},{-1,-1},{-1,1}};

bool BFS(Node start,Node end)
{
    int i;
    Node tempN;
    Node tempNM;
    queue<Node>Q;
    Q.push(start);
    maze[start.x][start.y]=-1;
    
    //while(tempN.x!=end.x&&tempN.y!=end.y&&Q.size!=0)
    while(Q.size()!=0)
    {
        tempN=Q.front();
        Q.pop();
        //遍歷8個方向全部的點
        for(i=0;i<8;i++)
        {
            tempNM.x=tempN.x+move[i].x;
            tempNM.y=tempN.y+move[i].y;
            //若是移動之后的點 位置是0 表示可以通過
            if(tempNM.x>=1&&tempNM.y>=1&&tempNM.x<=end.x&&tempNM.y<=end.y&&maze[tempNM.x][tempNM.y]==0)
            {
                //孩子結點入隊
                Q.push(tempNM);
                //已經嘗試過的點標記成-1
                maze[tempNM.x][tempNM.y]=-1;
                path[tempNM.x][tempNM.y]=tempN;
            }
        }
        
    }

    if(tempN.x==end.x&&tempN.y==end.y)
    {return true;}
    else
    {return false;}
    
    
}

void outputpath(Node end)
{
    //可以遞歸輸出
    Node temp=end;
    if(end.x==1&&end.y==1)
    {
        printf("(%d,%d)",end.x,end.y);
        return;
    }
    else
    {
        //取出指針的內容
        temp=path[temp.x][temp.y];
        outputpath(temp);
        if(temp.x!=1&&temp.y!=1)
        {printf("(%d,%d)",temp.x,temp.y);}
    }
    
    return;
    
}


int main()
{
    freopen("in.txt","r",stdin);
    int hang,lie,N;
    int i,j;
    scanf("%d",&N);
    while(N--)
    {
        //輸入部分
        scanf("%d%d",&hang,&lie);
        for(i=1;i<=hang;i++)
        {
            for(j=1;j<=lie;j++)
            {
                if(j==lie)
                {
                    scanf(" %d",&maze[i][j]);
                }
                else
                {
                    scanf("%d",&maze[i][j]);
                }
            }
        }
        
        
        Node start={1,1};
        //注意結構體的這種用中括號來賦值的方式
        Node end={hang,lie};
        
        //二維指針數組的規定初始值的方式
        //此時path是一個指向一維指針數組的指針
        path=new Node*[MAXL];
        for(i=0;i<=MAXL;i++)
        {path[i]=new Node[MAXH];}
        
        
        //調用BFS函數進行搜索 更新path矩陣信息 
        bool connect=BFS(start,end);
        if(connect)
            puts("YES");
        else
            puts("NO");
            
        
        //輸出路徑信息
        outputpath(end);
        
        printf("(%d,%d)\n",6,8);
        
    }
    
    
    return 0;
}


免責聲明!

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



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