1.dfs
dfs,即深度优先搜索,是一种用于遍历或搜索树或图的算法,深度优先是指每次都向更深的节点走,直到走不了,就回溯。
dfs最显著的特征在于其递归调用自身,展示一下dfs的代码基本实现:
void dfs(int x){
vis[x] = true;
for(int i = 0; i < a[x].size(); i++){
int v = a[x][i];
if(!vis[v]){
dfs(v);
}
}
}
在实际的dfs中会加入更多多的代码,以利用它的性质来进行各种操作。
2.bfs
bfs,即广度优先搜索,也是图上最基础、最重要的搜索算法之一,广度优先是指每次都尝试访问同一层的节点,如果同一层都访问完了,再访问下一层。
bfs会从起点s开始,一层一层扩散出去,处理完离s进的第i层后,再处理第i + 1层。这一操作用队列(先进先出)最合适,处理完第i层的节点a时,把a的第i + 1层的邻居放到队列尾部即可。
展示一下bfs的基本实现:
void bfs(int s){
queue<int>q;
vis[s] = true;
d[s] = 0; //用d[i]表示点i离起点s的距离
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = 0; i < a[x].size(); i++){
int v = a[x][i];
if(!vis[v]){
vis[v] = true;
d[v] = d[x] + 1;
q.push(v);
}
}
}
}
3.双向bfs
双向bfs是指双向广搜,他的基本思路就是从图上的起点和终点同时进行bfs,如果发现搜索的两端相遇了,就可以认为是获得了可行解。
4.剪枝
剪枝是搜索必用的优化手段,它可以大大降低普通搜索的复杂度。
dfs的常用剪枝技术,有:
1)可行性剪枝
对当前状态进行检查,如果当前条件不合法就不再继续。
2)最优性剪枝
在最优化问题的搜索过程中,如果当前花费的代价已经超过以前搜索的最优解,就直接退出(因为
已经没有意义)。
3)记忆化搜索
在递归的过程中,可以将计算出来的结果保存起来,以后要用到时就可以直接取出结果,避免了重复运算。
bfs的剪枝技术通常是判重,如果搜索到某一层时,出现了重复的状态,就“剪掉”。
5.A*
是一种在图形平面上,对于有多个节点的路径求出最低通过成本的算法。它属于图遍历和贪心最优算法,亦是bfs的改进。
在进行此算法的过程中,会定义从起点开始的距离函数g(x),到终点的距离函数h(x)、h*(x),以及每个点的估价函数f(x) = g(x) + h(x)。
A*算法每次从优先队列中取出一个f最小的元素,然后更新相邻的状态。如果h \(\leq\) h*,则A*算法能找到最优解。当h = 0时,A*算法变为dijkstra,而当h = 0并且边权为1时变为bfs。
6.IDDFS
IDDFS,即迭代加深搜索,它的本质还是dfs,只不过在搜索的同时带上了一个深度d,当d达到设定的深度时就返回,一般用于找最优解。如果一次搜索没有找到合法的解,就让设定的深度加一,重新从根开始。
7.IDA*
IDA*,即采用了迭代加深算法的A*算法。
由于IDA*改成了深度优先的方式,相对于A*算法,它的优点如下:
1)不需要判重,不需要排序,利于深度剪枝。
2)空间需求减少:每个深度下实际上是一个深度优先搜索,不过深度有限制,使用 DFS 可以减小空间消耗。
有优有缺,缺点:
1)重复搜索:即使前后两次搜索相差微小,回溯过程中每次深度变大都要再次从头搜索。