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個頂