期末複習之寬度優先搜尋

2021-06-27 22:20:20 字數 1637 閱讀 3068

寬度優先搜尋的演算法思想是比較簡單了

關鍵就是如何在有限的時間內寫出正確的寬度優先搜尋才是重點

不過在開始還是要弄明白,看到乙個題,到底是用寬度優先搜尋還是用深度優先搜尋,所以,我們要明白寬度優先搜尋相對於深度優先搜尋的優點

1.方便找到最優解(一般第乙個解就是最優的,而深度優先搜尋必須要遍歷完所有可能解才能確定)

2.沒有遞迴(所以狀態轉換更加直觀明了)

所以寬度優先搜尋適合處理:

迷宮類問題,魔板類問題(因為這些一般都要求最優解)

最簡單的寬度優先搜尋包括:

1.記錄要走的下乙個狀態,並放入佇列

2.在正確的狀態終結搜尋過程

對於第一點,如何記錄當前狀態,對於迷宮或魔板,一般是乙個二維陣列,當然也可以用字串來儲存,這裡建議放入乙個結構體中,方便記錄狀態的其他引數

一般寬度優先搜尋還包括:

1.記錄狀態轉移的路徑

2.搜尋的深度

路徑可以通過乙個陣列放入結構體中,已知路徑,深度當然也可以得到

優化:

1.去重(記錄已經走過的狀態)

無環迷宮當然不會有重複的狀態,但是有環迷宮或者魔板一般都會出現重複的狀態,所以如何去重是優化乙個寬度優先搜尋的關鍵,不過,對於乙個魔板問題,給定乙個狀態,如何快速地確定這個狀態是不是重複的,最簡單有效的辦法就是hash對映,但是如何把乙個狀態轉換為陣列的下標就是關鍵了,這裡使用康托展開:

康拓展開,就是求乙個全排列是第幾個排列

比如給定1234的全排列,問3241是由小到大是第幾個排列,可以看出,1234應該是第乙個排列,而1243應該是第二個排列,4321應該是最後乙個排列,也就是第4!個

而康託展開就給出了乙個系統求全排列的方法:

x=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!

其中,a[n]表示比當前數小的數還有多少種(因為是由小到大)

比如1234,比1小的數沒有,那麼就是0,再看2,發現比2小的數只有1,但已經出現在第一位了,所以也是0,3,4同理,那麼1234康托展開就是0*3!+0*2!+0*1!+0*0!=0

再比如1243,1,2都是0,再看4,比4小的只有3,那麼1234的康托展開就是0*3!+0*2!+1*1!+0*0!=1

以下是一段12345678全排列的康托展開

int u[8] = ; //預先儲存好7!,6!之類的值

int cantor(int a) ; //未訪問過的數字,1~8

int num = 0; //康托展開的結果

for(int i = 0; i < 8; i++)

is_visited[a[i]] = 1; //將訪問過的數字置為1

num += x * u[i];

} return num;

}

這樣,我們就可以把乙個魔板狀態壓縮成乙個小於8!=40320的數字,然後把這個作為陣列下標來記錄已經訪問過的狀態

一些注意事項:

1.全域性變數的初始化

2.終結條件的準確判斷(比深搜要方便)

一些錯誤型別:

1.如果超時,一般是對stl庫使用過多,或者頻繁呼叫函式

2.如果超記憶體,一般是搜尋深度過深,這時要考慮到去重(或者是開了很大的陣列)

寬度優先搜尋

include using namespace std const int n 700 const int inf 0x3f3f3f3f int dir 10 int n,a,b,ans 1000000 flag 0 int floor n struct node int check node tm...

寬度優先搜尋

寬度優先搜尋演算法 又稱廣度優先搜尋 是最簡便的圖的搜尋演算法之一,這一演算法也是很多重要的圖的演算法的原型。dijkstra單源最短路徑演算法和prim最小生成樹演算法都採用了和寬度優先搜尋類似的思想。其別名又叫bfs,屬於一種盲目搜尋法,目的是系統地展開並檢查圖中的所有節點,以找尋結果。換句話說...

寬度優先搜尋

寬度優先搜尋也是搜尋的手段之一。它與深度優先搜尋類似,從某個狀態出發探索所有可以到達的狀態。const int inf 100000000 使用pair表示狀態時,使用typedef會更加方便一些 typedef pair p char maze max n max m 1 表示迷宮的字串陣列 in...