1. 程式人生 > >【昊昊帶你學】寬搜(BFS)

【昊昊帶你學】寬搜(BFS)

**************************轉載請註明出處!******************************

         很久很久以前,我講了深搜(這到底是有多久 - -|||)。對應的當然就得有寬搜。搜尋的概念上次深搜已經講過了,可以去“複習”一下。

         既然搜尋搜的是狀態之間的轉移,那麼我們就可以將這些狀態看做一棵樹。假設我們有一個田字格,每個格子可能是白色或黑色,我們想知道有多少種情況。此時,田字格每種情況就相當於一個狀態,我們可以通過狀態之間的轉移來講所有情況“搜尋”出來。

 

         上面列舉了所有的狀態,而那些先表示了狀態之間的一些關係——只有一個格子顏色不同。而最初,我們不知道有這些情況。所以就要設計一種狀態轉移的方法來“遍歷”出一顆“狀態樹”,這棵樹的節點是每種情況。根據某種方式,由一種狀態出發就可以搜尋出想要的答案。

         比如,我們從空白狀態開始。給這個田字格染色。於是就成了下面這個情況。圖片左肩上的數字表示狀態搜尋的順序。很明顯,這些狀態構成了一棵樹。根節點是一個空田字格。下面一層是有兩個塊被染色的狀態,再下面是3塊被染色,最後是全染色的狀態。當然,搜尋過的狀態需要標記,以便於某些狀態不會被重複搜到。當然你也可以設計一種特殊的演算法,似的不需要判重。搜尋過程如下:由1找到2、3、4、5——2找到6、7、8——3找到9、10——4找到11——6找到12、13——7找到14——9找到15——12找到16.

 

         寬搜也就由這個搜尋的順序得名,搜尋的順序,與樹的寬度優先遍歷順序一致。寬搜一個用途就是對一些最優問題進行求解。從上圖可以看到,轉移次數最少的情形最先被搜尋到。到求最優解問題中,就可以看做是代價小的情況會被最先搜尋到。但寬搜也有缺點,就是要記錄每種狀況的各種引數。相比較深搜的回溯演算法,只改變部分引數繼續搜尋,空間複雜度要更高。

         下面就來談談寬搜的實現。其實,根據上面的描述,大家應該都想到了佇列實現。搜尋的一個迴圈內,取頭結點,進行狀態的擴充套件,擴充套件到的新狀態判重之後從隊尾進隊。如此迴圈,直到搜尋到答案或者佇列為空。看~~~整起來很簡單~

         while (佇列非空) do

                   狀態 ← DEQUEUE(Q)

                   (迴圈,狀態擴充套件)

                            If (狀態不重複)

                                     ENQUEUE(狀態)

                   狀態標記(已搜過)

不知道上面這個,昊式獨家的中英雜交虛擬碼能不能把這個過程講明白。當然,搜這些狀態還要很多技巧,需要操練。不能立即明白也沒關係,多多體會。