1. 程式人生 > >搜索專題總結

搜索專題總結

nbsp 人工 init 需求 space tdi turn emp cout

最近學習了一些搜索方面的知識,寫一篇文章來總結一下。

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*的用途比較廣泛。

如果有錯誤的地方,請大家多多指教。

搜索專題總結