搜索專題總結
最近學習了一些搜索方面的知識,寫一篇文章來總結一下。
1.雙向BFS
好像聽有的人說這也叫meet in middle,確實,這樣說更加的形象一些。原來的BFS都是從起點出發進行搜索,直到搜索到終點為止。
而雙向BFS提高了算法的效率,從起始狀態與終止狀態同時出發,一同進行搜索,這樣搜索的範圍就可以減少。
通常的BFS用到一個隊列,所以雙向BFS就是用兩個隊列,實現的過程也比較簡單。
下面可以利用8數碼問題來看一下雙向BFS。
題目鏈接:http://codevs.cn/problem/1225/
這道題搜索的範圍較大,BFS會超時,所以用雙向BFS。
過程很好理解,個人感覺當終止狀態與初始狀態都是給定的時候,可以嘗試雙向BFS。
1 #include<cstdio>
2 #include<algorithm>
3 #include<map>
4 #include<vector>
5 #include<queue>
6 #include<iostream>
7 using namespace std;
8 string s,t;
9 vector <int> a[10];
10 map <string,int> mp1,mp2;
11 queue <string> q1,q2;
12 void init(){
13 a[0].push_back(1); a[0].push_back(3);
14 a[1].push_back(0); a[1].push_back(2); a[1].push_back(4);
15 a[2].push_back(1); a[2].push_back(5);
16 a[3].push_back(0); a[3].push_back(4); a[3].push_back(6);
17 a[4].push_back(1); a[4].push_back(3); a[4].push_back(5); a[4].push_back(7);
18 a[5].push_back(2); a[5].push_back(4); a[5].push_back(8);
19 a[6].push_back(3); a[6].push_back(7);
20 a[7].push_back(4); a[7].push_back(6); a[7].push_back(8);
21 a[8].push_back(5); a[8].push_back(7);
22 }
23 void bibfs(){
24 q1.push(s); q2.push(t);
25 while (!q1.empty() || !q2.empty()) {
26 if (!q1.empty()) {
27 string now1=q1.front(); q1.pop();
28 int st1=mp1[now1];
29 for (int i=0; i<9; i++) if (now1[i]==‘0‘){
30 for (int j=0; j<a[i].size(); j++){
31 swap(now1[i],now1[a[i][j]]);
32 if (mp2[now1]) {
33 cout<<st1+mp2[now1]-1<<endl;
34 return;
35 }
36 if (!mp1[now1]) {
37 q1.push(now1);
38 mp1[now1]=(st1+1);
39 }
40 swap(now1[i],now1[a[i][j]]);
41 }
42 }
43 }
44 if (!q2.empty()) {
45 string now2=q2.front(); q2.pop();
46 int st2=mp2[now2];
47 for (int i=0; i<9; i++) if (now2[i]==‘0‘){
48 for (int j=0; j<a[i].size(); j++){
49 swap(now2[i],now2[a[i][j]]);
50 if (mp1[now2]) {
51 cout<<st2+mp1[now2]-1<<endl;
52 return;
53 }
54 if (!mp2[now2]) {
55 q2.push(now2);
56 mp2[now2]=(st2+1);
57 }
58 swap(now2[i],now2[a[i][j]]);
59 }
60 }
61 }
62 }
63 }
64 int main(){
65 ios::sync_with_stdio(false);
66 cin>>s;
67 t="123804765";
68 init();
69 mp1[s]=1; mp2[t]=1;
70 if (s==t) cout<<"0"<<endl;
71 else bibfs();
72 return 0;
73 }
2.叠代深搜
叠代深搜,IDDFS,用於解決狀態樹很大(甚至是無限的),但是目標狀態很淺的問題。
舉個例子,一棵搜索狀態樹有兩個分支,A分支與B分支。
A分支下面有1000000000個狀態,而B分支只有目標狀態一個狀態,
這時候,要是用傳統的DFS,如果進入了A分支,那就非常麻煩了。
而叠代加深搜索不會這兩樣,它限制搜索的深度,要是沒有搜索到目標狀態
再把限制深度+1,這樣就能很好地解決上面舉的這個誇張的例子。
再舉個例子,一棵狀態樹,有100000000個分支,這個時候要是用傳統的BFS,隊列中的狀態樹最多可以達到100000000個,這樣的話空間就要吃不消了,而叠代加深搜索沒有很大的空間需求,它做到了兩個算法的一個綜合。
關於時間復雜度,IDDFS並沒有比傳統意義上的BFS慢多少。
而空間復雜度,它與傳統DFS是一樣的。
總的來說,當目標狀態較淺,可以用BFS,但BFS的空間又不夠時,可以選擇叠代加深搜索。
3.A* IDA*
個人覺得A*是一個高深的東西,但是在OI中,A*主要是用於剪枝,並沒有在人工智能中用途更加廣泛。A*需要一個估價函數,通常就是當前狀態到目標狀態至少還需要多少步,如果估值與已走步數相加超過規定步數,那就剪枝。這裏說到了限定步數,這在IDDFS中似曾相識,確實,IDDFS與A*結合起來就變成了IDA*。在OI中,IDA*的用途比較廣泛。
如果有錯誤的地方,請大家多多指教。
搜索專題總結