搜索专题总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搜索专题总结相关的知识,希望对你有一定的参考价值。

最近学习了一些搜索方面的知识,写一篇文章来总结一下。

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*的用途比较广泛。

 

如果有错误的地方,请大家多多指教。

 

以上是关于搜索专题总结的主要内容,如果未能解决你的问题,请参考以下文章

搜索专题总结

kuangbin专题总结一 简单搜索

总结($20191101$)

专题总结-二叉树

专题总结—二分查找与旋转排序数组

kuangbin带你飞专题一 简单搜索 题解