标签:目标 超过 剪枝 algorithm map out namespace 时间 关于
最近学习了一些搜索方面的知识,写一篇文章来总结一下。
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*的用途比较广泛。
如果有错误的地方,请大家多多指教。
标签:目标 超过 剪枝 algorithm map out namespace 时间 关于
原文地址:http://www.cnblogs.com/moerblack/p/7497959.html