文章目录
搜索算法是利用计算机的高性能来有目的的穷举一个问题解空间的部分或所有的可能情况,从而求出问题的解的一种方法。现阶段一般有枚举算法、深度优先搜索、广度优先搜索、 A ∗ A^* A∗算法、回溯算法、蒙特卡洛树搜索、散列函数等算法。
1.深度优先搜索
深度优先搜索,又叫 D F S DFS DFS,顾名思义就是按照深度优先的顺序对于“问题状态空间”进行搜索的算法。
深度优先搜索的核心思想
举例说明一下:下图是一个无向图,如果我们从A点发起深度优先搜索,则我们可能得到如下的一个访问过程:
A
−
>
B
−
>
E
A->B->E
A−>B−>E(没有路了!回溯到
A
A
A)
−
>
C
−
>
F
−
>
H
−
>
G
−
>
D
->C->F->H->G->D
−>C−>F−>H−>G−>D(没有路,最终回溯到
A
A
A,
A
A
A也没有未访问的相邻节点,本次搜索结束)。纯粹的不撞南墙不回头。
基本算法框架:
int dfs(int k) {
if(到目的地)
输出解;
else {
for(int i=1;i<=算符总数;i++) {
if(满足条件) {
保存条件
dfs(k+1);
恢复:保存条件之前的结果(回溯一步)
}
}
}
}
回溯:主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。不能把当前的条件保留下来影响后面的搜索(当然,有一些条件是可以不用改的,只要你能保证它不会影响后续的搜索或者它在后续会被覆盖掉)。
2.广度优先搜索
广度优先搜索,又称宽度优先搜索或者 B F S BFS BFS,是一种最简便的图的搜索算法之一。
广度优先搜索的核心思想
从初始节点开始,应有算符生成第一层节点,检查目标节点是否在这些节点中,若没有,再用产生规则将所有的第一层的节点逐一延展,得到第二层节点,并逐一检查第二层中是否有目标节点,若没有…依次检查下去,直到发现目标节点。
基本算法框架:
举个例子:我们从 ( b x , b y ) (bx,by) (bx,by)开始,要在一个长宽分别为 n n n和 m m m的矩阵中搜索一个节点 ( x x , y y ) (xx,yy) (xx,yy)。
int ex[4]={1,0,-1,0};
int ey[4]={0,1,0,-1};
void BFS(int bx,int by) {
vis[bx][by]=1;
queue<int> a,b;
a.push(bx),b.push(by);
while(a.size()) {
int x=a.front(),y=b.front();
a.pop(),b.pop();
if(x==xx && y==yy) {
printf("YES");
return ;
}
for(int i=0;i<4;i++) {
int nx=x+ex[i],ny=y+ey[i];
if(nx>0 && ny>0 && nx<=n && ny<=m && vis[nx][ny]==0) {
vis[nx][ny]=1;
a.push(nx),b.push(ny);
}
}
}
printf("NO");
return ;
}
DFS和BFS的区别:
D F S DFS DFS可以说是碰运气似的乱搜索,可能会出现答案就在身边,而却在其他地方搜索了很久,而且第一时间找到的答案不一定就是最佳答案,所以必须要将所有的路径都搜索完。
而 B F S BFS BFS就完全不同了,它就是稳打稳扎,一步一步慢慢向前。而且第一时间搜索到的答案一定是最佳答案。但当答案离初始节点很远时,时间和空间就会大幅度提高。
剪枝
1.优化搜索顺序
在一些搜索问题中,搜索树的各个层次、各个分支之间的顺序是不固定的。不同的搜索顺序会产生不同的搜索树,会导致搜索效率变高。
2.排除等效冗余
当我们能判断从当前节点的不同分支搜索下去结果是一样的,那我们搜索一次就可以了。
3.可行性剪枝
如果我们可以判断当前节点搜索下去绝对找不到结果,我们就不用找了。
4.最优性剪枝
在最优化问题中,如果当前花费的代价已经超过了当前搜索到的最优解,我们就可以不在搜索下去了。
5.记忆化
可以记录每个状态的搜索结果,再重复搜索的时候直接检索并返回。这就好比我们用DFS时,标记一个节点是否已经被访问过。