1. 程式人生 > >BFS(一):廣度優先搜尋的基本思想

BFS(一):廣度優先搜尋的基本思想

      廣度優先搜尋BFS(Breadth First Search)也稱為寬度優先搜尋,它是一種先生成的結點先擴充套件的策略。

      在廣度優先搜尋演算法中,解答樹上結點的擴充套件是按它們在樹中的層次進行的。首先生成第一層結點,同時檢查目標結點是否在所生成的結點中,如果不在,則將所有的第一層結點逐一擴充套件,得到第二層結點,並檢查第二層結點是否包含目標結點,……,對層次為n+1的任一結點進行擴充套件之前,必須先考慮層次完層次為n的結點的每種可能的狀態。因此,對於同一層結點來說,求解問題的價值是相同的,可以按任意順序來擴充套件它們。通常採用的原則是先生成的結點先擴充套件。

      為了便於進行搜尋,要設定一個表儲存所有的結點。由於在廣度優先搜尋演算法中,要滿足先生成的結點先擴充套件的原則,所以儲存結點的表一般採用佇列這種資料結構。

      在編寫程式時,可用陣列q模擬佇列。front和rear分別表示隊頭指標和隊尾指標,初始時front=rear=0。

      元素x入隊操作為  q[rear++]=x;

      元素x出隊操作為  x =q[front++];

      廣度優先搜尋演算法的搜尋步驟一般是:

      (1)從佇列頭取出一個結點,檢查它按照擴充套件規則是否能夠擴充套件,如果能則產生一個新結點。

       (2)檢查新生成的結點,看它是否已在佇列中存在,如果新結點已經在佇列中出現過,就放棄這個結點,然後回到第(1)步。否則,如果新結點未曾在佇列中出現過,則將它加入到佇列尾。

      (3)檢查新結點是否目標結點。如果新結點是目標結點,則搜尋成功,程式結束;若新結點不是目標結點,則回到第(1)步,再從佇列頭取出結點進行擴充套件。

      最終可能產生兩種結果:找到目標結點,或擴充套件完所有結點而沒有找到目標結點。

      如果目標結點存在於解答樹的有限層上,廣度優先搜尋演算法一定能保證找到一條通向它的最佳路徑,因此廣度優先搜尋演算法特別適用於只需求出最優解的問題。當問題需要給出解的路徑,則要儲存每個結點的來源,也就是它是從哪一個節點擴充套件來的。

      對於廣度優先搜尋演算法來說,問題不同則狀態結點的結構和結點擴充套件規則是不同的,但搜尋的策略是相同的。廣度優先搜尋演算法的框架一般如下:

void  BFS()

{

    佇列初始化;

    初始結點入隊;

    while (佇列非空)

    {  

          隊頭元素出隊,賦給current;

          while  (current 還可以擴充套件)

          {

              由結點current擴展出新結點new;

              if  (new 重複於已有的結點狀態) continue;

              new結點入隊;

              if  (new結點是目標狀態)

              {

                    置flag= true;    break; 

               }

          }

      }

}

       對於不同的問題,用廣度優先搜尋法的演算法基本上都是一樣的。但表示問題狀態的結點資料結構、新結點是否為目標結點和是否為重複結點的判斷等方面則有所不同。對具體的問題需要進行具體分析,這些函式要根據具體問題進行編寫。

【例1】黑色方塊

      有一個寬為W、高為H的矩形平面,用黑色和紅色兩種顏色的方磚鋪滿。一個小朋友站在一塊黑色方塊上開始移動,規定移動方向有上、下、左、右四種,且只能在黑色方塊上移動(即不能移到紅色方塊上)。編寫一個程式,計算小朋友從起點出發可到達的所有黑色方磚的塊數(包括起點)。

      例如,如圖1所示的矩形平面中,“#”表示紅色磚塊,“.”表示黑色磚塊,“@”表示小朋友的起點,則小朋友能走到的黑色方磚有28塊。

      (1)程式設計思路。

      採用廣度優先搜尋法解決這個問題。

      用陣列q模擬佇列操作,front為隊頭指標,rear為隊尾指標,初始時front=rear=0。

      入隊操作為 q[rear++]=cur;

      出隊操作為 cur=q[front++]。

      程式中定義方磚的位置座標(x,y)為Node型別,定義陣列int visit[N][N]標記某方磚是否已走過,visit[i][j]=0表示座標(i,j)處的方磚未走過,visit[i][j]=1表示座標(i,j)處的方磚已走過。初始時visit陣列的所有元素值均為0。

      具體演算法步驟為:

      ① 將出發點(startx,starty)入佇列q,且置visit[startx][starty]=1,表示該處的方磚已被處理,以後不再重複搜尋。

      ② 將佇列q的隊頭元素出棧,得到一個當前方磚cur,黑色方磚計數(sum++),沿其上、下、左、右四個方向上搜索未走過的黑色方磚,將找到的黑色方磚的座標入佇列q。

      ③ 重複執行②,直至佇列q為空,則求出了所有能走過的黑色方磚數。

      (2)源程式。

#include <iostream>

using namespace std;

#define N 21

struct Node

{

       int x;

       int y;

};

int dx[4]={-1,1,0,0};

int dy[4]={0,0,-1,1};

char map[N][N];

int visit[N][N];

int bfs(int startx, int starty,int w,int h)

{

       Node q[N*N],cur,next;   // q為佇列

       int  front,rear;        // front為隊頭指標,rear為隊尾指標

       int i,x,y,sum;    

       front=rear=0;           // 佇列q初始化

       sum=0;

       cur.x=startx;   cur.y=starty; 

       visit[startx][starty]=1;

       q[rear++]=cur;          // 初始結點入隊

       while(rear!=front)      // 佇列不為空

       {

              cur=q[front++];     // 隊頭元素出隊

              sum++;              // 方磚計數

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

              {

                  x=cur.x+dx[i];  y=cur.y+dy[i];

                 if(x >=0 && x<h && y>=0 && y<w && map[x][y]!='#' && visit[x][y]==0)

                 {

                        visit[x][y] = 1;

                        next.x=x;  next.y=y;  // 由cur擴展出新結點next

                        q[rear++]=next;       // next結點入隊

                  } 

              }

       }

       return sum;

}

int main()

{

   int i,j,pos_x,pos_y,w,h,sum;

   while(1)

   {

       cin>>w>>h;

        if (w==0 && h==0) break;

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

       {

          for(j=0;j<w;j++)

          {

              cin>>map[i][j];

              if (map[i][j]=='@')

             {

                pos_x = i;

                pos_y = j;

             }

              visit[i][j] = 0;

         }

      }

      sum=bfs(pos_x, pos_y,w,h);

      cout<<sum<<endl;

   }

   return 0;

相關推薦

BFS廣度優先搜尋基本思想

      廣度優先搜尋BFS(Breadth First Search)也稱為寬度優先搜尋,它是一種先生成的結點先擴充套件的策略。       在廣度優先搜尋演算法中,解答樹上結點的擴充套件是按它們在樹中的層次進行的。首先生成第一層結點,同時檢查

圖解演算法學習筆記廣度優先搜尋

本章內容;        學習使用新的資料結構圖來建立網路模型;        學習廣度優先搜尋;        學習有向圖和無向圖;        學習拓撲排序,這種排序演算法指出了節點之間的依賴關係。 1)圖簡介 假設你住在舊金山,要從雙子峰前往金門大橋。你想乘

二叉樹 深度優先搜尋DFS廣度優先搜尋BFS

深度優先搜尋演算法(Depth First Search) DFS是搜尋演算法的一種。它沿著樹的深度遍歷樹的節點,儘可能深的搜尋樹的分支。 當節點v的所有邊都己被探尋過,搜尋將回溯到發現節點v的那條邊的起始節點。這一過程一直進行到已發現從源節點可達的所有節點為止。 如果還存在未被發現的節點,

圖的深度優先搜尋DFS廣度優先搜尋BFS及其Java實現

一、背景知識:(1)圖的表示方法:鄰接矩陣(二維陣列)、鄰接表(連結串列陣列【連結串列的連結串列】)。(2)圖的搜尋方法:深度優先搜尋(DFS)和廣度優先搜尋(BFS)。二、圖的搜尋:      1、深度優先搜尋(DFS):         (1)用棧記錄下一步的走向。訪問一

圖的遍歷演算法-深度優先搜尋演算法dfs廣度優先搜尋演算法bfs

一、前提須知圖是一種資料結構,一般作為一種模型用來定義物件之間的關係或聯絡。物件:頂點(V)表示;物件之間的關係或者關聯:通過圖的邊(E)來表示。一般oj題中可能就是點與點,也有可能是具體生活中的物體圖

ATP的OpenCV筆記對圖片的基本操作

寫在前面 ATP成功進化成棄坑大師。。 主要是正式開課以後自己亂搞著玩兒的東西就不想管它了QAQ。。。Python學會了以後也懶得往部落格裡寫了。。 這次打算開的坑emmm是上課講的內容?由於要記住的函式用法太多ATP懶得每次遇到都百度所以相當於在blog裡面記一下嗯就是這樣。 OpenCV是個可以用

【淺談遞迴】遞迴的基本思想

1、遞迴簡述 遞迴作為程式設計裡最為重要的程式設計方法之一,其對於解決某些複雜的問題十分有效,並且相對於迭代,其過程在直觀上更容易理解。而且不像迭代自己需要維護許多變數,遞迴也更容易實現。 2、遞迴的基本思想 遞歸併不是簡單的自己呼叫自己,也不是簡單的互動

圖 | 兩種遍歷方式深度優先搜尋DFS、深搜廣度優先搜尋BFS、廣搜

前邊介紹了有關圖的 4 種儲存方式,本節介紹如何對儲存的圖中的頂點進行遍歷。常用的遍歷方式有兩種:深度優先搜尋和廣度優先搜尋。 深度優先搜尋(簡稱“深搜”或DFS) 圖 1 無向圖 深度優先搜尋的過程類似於樹的先序遍歷,首先從例

BFS雙向廣度優先搜尋

      所謂雙向廣度搜索指的是搜尋沿兩個方向同時進行:(1)正向搜尋:從初始結點向目標結點方向搜尋;(2)逆向搜尋:從目標結點向初始結點方向搜尋;當兩個方向的搜尋生成同一子結點時終止此搜尋過程。       廣度雙向搜尋通常有兩種方法:(1)兩

everything用於行動硬碟資料管理離線搜尋

使用【everything檔案搜尋軟體】建立行動硬碟列表,實現離線檔案(夾)搜尋 第一步:開啟檔案列表。 第二步:另存離線檔案列表 2.1 複製行動硬碟某個分割槽的名稱。 2.2 檔案列表另存為 第三步:第一次搜尋,儲存搜尋結

二叉樹的深度優先遍歷DFS廣度優先遍歷BFS

最近在練習劍指offer上的題,討論區看到有人提到深度優先遍歷和廣度優先遍歷,就查了一點相關知識點。 深度優先遍歷(Depth First Search,簡稱DFS)又稱深度優先搜尋,遍歷的過程是 從某個頂點出發,首先訪問這個頂點,然後找出剛訪問這個結點的第一個未被訪問的鄰結點,然後

LeetCode-105.從前序與中序遍歷序列構造二叉樹相關話題深度優先搜尋

根據一棵樹的前序遍歷與中序遍歷構造二叉樹。 注意: 你可以假設樹中沒有重複的元素。 例如,給出 前序遍歷 preorder = [3,9,20,15,7] 中序遍歷 inorder = [9,3,15,20,7] 返回如下的二叉樹: 3 / \ 9

LeetCode-106.從中序與後序遍歷序列構造二叉樹相關話題深度優先搜尋

根據一棵樹的中序遍歷與後序遍歷構造二叉樹。 注意: 你可以假設樹中沒有重複的元素。 例如,給出 中序遍歷 inorder = [9,3,15,20,7] 後序遍歷 postorder = [9,15,7,20,3] 返回如下的二叉樹: 3 / \

LeetCode-117.填充同一層的兄弟節點II相關話題廣度優先

給定一個二叉樹 struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; } 填充它的每個 next 指標,讓這個指標指向其下一個右側節點。如果找不到下

演算法題三十二叉搜尋BST的後序遍歷序列

題目描述 輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的陣列的任意兩個數字都互不相同。 分析 後序遍歷序列中,最右邊數字也就是根結點,會把數集分為左右兩部分,左邊數集都小於root,右邊數集都大於root。左

LeetCode-133.克隆圖相關話題廣度優先

克隆一張無向圖,圖中的每個節點包含一個 label (標籤)和一個 neighbors (鄰接點)列表 。 OJ的無向圖序列化: 節點被唯一標記。 我們用 # 作為每個節點的分隔符,用 , 作為節點標籤和鄰接點的分隔符。 例如,序列化無向圖 {0,1,2#1,2#2,2}。 該圖

LeetCode-127.單詞接龍相關話題廣度優先

給定兩個單詞(beginWord 和 endWord)和一個字典,找到從 beginWord 到 endWord 的最短轉換序列的長度。轉換需遵循如下規則: 每次轉換隻能改變一個字母。 轉換過程中的中間單詞必須是字典中的單詞。 說明: 如果不存在這樣的轉換序列,返回 0。 所有單詞具有相同的

LeetCode-116.填充同一層的兄弟節點相關話題廣度優先

給定一個二叉樹 struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; } 填充它的每個 next 指標,讓這個指標指向其下一個右側節點。如果找不到下一個右側節點,則將

圖的深度優先遍歷DFS廣度優先遍歷BFS

1 建立測試圖(鄰接矩陣和鄰接表儲存形式) 首先建立一個圖用於後續程式碼的測試,在此以無向圖為例,且所有邊的權值都為1。儲存方式分別為鄰接矩陣和鄰接表(見上一篇介紹) 鄰接矩陣: class Graph{ constructor(v,vr){ let len = v.le

1003:深度優先遍歷DFS&廣度優先遍歷BFS

Problem Description 設有一連通有向圖,其頂點值為字元型並假設各值互不相等,採用鄰接表表示法儲存表示,求其廣度優先遍歷序列。  Input 有多組測試資料,每組資料的第一行為兩個整數n和e,表示n個頂點和e條邊(0<n<20);第二行為其n個頂