寬度優先搜尋BFS

2021-06-18 10:17:40 字數 2757 閱讀 5634

寬度優先搜尋(bfs,breadth-first search)也是搜尋的手段之一。它與深度優先搜尋類似,從某個狀態出發探索所有可以到達的狀態。

與深度優先搜尋的不同之處在於搜尋的順序,寬度優先搜尋總是先搜尋距離初始狀態近的狀態。也就是說,它是按照開始狀態→只需1次轉移就可以到達的所有狀態→只需2次轉移就可以到達的所有狀態→……這樣的順序進行搜尋。對於同乙個狀態,寬度優先搜尋只經過一次,因此複雜度為o(狀態數×轉移的方式)。

狀態轉移的順序

深度優先搜尋(隱式地)利用了棧進行計算,而寬度優先搜尋則利用了佇列。搜尋時首先將初始狀態新增到佇列裡,此後從佇列的最前端不斷取出狀態,把從該狀態可以轉移到的狀態中尚未訪問過的部分加入佇列,如此往復,直至佇列被取空或找到了問題的解。通過觀察這個佇列,我們可以就知道所有的狀態都是按照距初始狀態由近及遠的順序被遍歷的。

迷宮的最短路徑給定乙個大小為n×m的迷宮。迷宮由通道和牆壁組成,每一步可以向鄰接的上下左右四格的通道移動。請求出從起點到終點所需的最小步數。請注意,本題假定從起點一定可以移動到終點。

限制條件

樣例輸入

n=10

,m=10

(迷宮如下圖所示。

'#',

'.',

's',

'g'分別表示牆壁、通道、起點和終點)

#s######.#

......

#..#

.#.##.##.#

.#........

##.##.####

....

#....#

.#######.#

....

#.....

.####.###.

....

#...g#

輸出

22
寬度優先搜尋按照距開始狀態由近及遠的順序進行搜尋,因此可以很容易地用來求最短路徑、最少操作之類問題的答案。這個問題中,狀態僅僅是目前所在位置的座標,因此可以構造成pair或者編碼成int來表達狀態。當狀態更加複雜時,就需要封裝成乙個類來表示狀態了。轉移的方式為四方向移動,狀態數與迷宮的大小是相等的,所以複雜度是o(4×n×m)=o(n×m)。

寬度優先搜尋中,只要將已經訪問過的狀態用標記管理起來,就可以很好地做到由近及遠的搜尋。這個問題中由於要求最短距離,不妨用d[n][m]陣列把最短距離儲存起來。初始時用充分大的常數inf來初始化它,這樣尚未到達的位置就是inf,也就同時起到了標記的作用。

在今後的程式中,使用像inf這樣充分大的常數的情況還很多。不把inf當作例外,而是直接參與普通運算的情況也很常見。這種情況下,如果inf過大就可能帶來溢位的危險。

假設inf=231-1。例如想用d[nx][ny]=min(d[nx][ny], d[x][y]+1)來更新d[nx][ny],就會發生inf+1=-231的情況。這一問題中d[x][y]總不等於inf,所以沒有問題。但是為了防止這樣的問題,一般會將inf設為放大2~4倍也不會溢位的大小(可參考2.5節floyd-warshall演算法等)。

因為要向4個不同方向移動,用dx[4]和dy[4]兩個陣列來表示四個方向向量。這樣通過乙個迴圈就可以實現四方向移動的遍歷。

const

intinf

=100000000

;// 使用pair表示狀態時,使用typedef會更加方便一些

typedef

pair

<

int,

int>p;

// 輸入

char

maze

[max_n

][max_m +1

];// 表示迷宮的字串的陣列

intn,m

;intsx,

sy;// 起點座標

intgx,gy

;// 終點座標

intd

[max_n

][max_m

];// 到各個位置的最短距離的陣列

// 4個方向移動的向量

intdx[4

]=,dy

[4]=

;// 求從(sx, sy)到(gx, gy)的最短距離

// 如果無法到達,則是inf

intbfs()}

}returnd[

gx][

gy];

}void

solve

()

寬度優先搜尋與深度優先搜尋一樣,都會生成所有能夠遍歷到的狀態,因此需要對所有狀態進行處理時使用寬度優先搜尋也是可以的。但是遞迴函式可以很簡短地編寫,而且狀態的管理也更簡單,所以大多數情況下還是用深度優先搜尋實現。反之,在求取最短路時深度優先搜尋需要反覆經過同樣的狀態,所以此時還是使用寬度優先搜尋為好。

寬度優先搜尋會把狀態逐個加入佇列,因此通常需要與狀態數成正比的記憶體空間。反之,深度優先搜尋是與最大的遞迴深度成正比的。一般與狀態數相比,遞迴的深度並不會太大,所以可以認為深度優先搜尋更加節省記憶體。

此外,也有採用與寬度優先搜尋類似的狀態轉移順序,並且注重節約記憶體占用的迭代加深深度優先搜尋(iddfs,iterative deepening depth-first search)。iddfs是一種在最開始將深度優先搜尋的遞迴次數限制在1次,在找到解之前不斷增加遞迴深度的方法。這種方法會在4.5節詳細介紹。

寬度優先搜尋(BFS)

bfs,其英文全稱是breadth first search。0 1 4 2 3思路 從圖中某個節點出發,將該結點入隊,標記為已訪問。然後輸出佇列的隊首 第一次為起點 將隊首從佇列中刪除,訪問該結點的鄰接表,將未標記的相鄰結點入隊,並且標記為已訪問。接下來迴圈操作第二句話。按照上邊的圖,假設出發點為...

寬度優先搜尋bfs

好吧,今天看了bfs,其實發現基本思想也是不過如此。只是,應用還是不太會。bfs是寬度優先,從根節點開始,依次訪問它的所有鄰接點,然後再按順序訪問鄰接點的鄰接點,先被訪問的點的鄰接點先被訪問。由於要按這樣的順序訪問,所以需要用到佇列。求最短路徑和迷宮型別的題目都可以利用bfs.下面是基本步驟 1 從...

寬度優先搜尋BFS

小問 如果題目問最短路徑,除了bfs還可能是什麼演算法?如果問最長路徑呢?答案 最常見的演算法中,bfs還可以用dp 如果是最長路徑的話,可以用dfs和dp。小點 bfs的標配是佇列,dfs的標配是棧。如果是層級遍歷的話,實現步驟可以大體分三步 建立乙個佇列,把起始點都放到裡面去 第一層節點 whi...