写了很多题以后,突然乱掉了,尤其是递归和dfs傻傻分不清了,现在来总结一下
首先他们是一个循序渐进的事情,然后他们解决什么问题呢?解决有多少种解决办法这种问题,最优解的话就用贪心和动归去做好了。
1、最开始是递归,就是一个很简单的自己调用自己的一个操作,递归的一般姿势如下
void f()
{
if(符合边界条件)
{
///
return;
}
//某种形式的调用
f();
}
2、再其次就是回溯了
回溯是一种算法思想,他就相当于递归中的剪枝。剪枝的意思也就是说对已经知道错误的结果没必要再枚举接下来的答案了,比如一个有序数列1,2,3,4,5,我要找和为5的所有集合,从前往后搜索我选了1,然后2,然后选3的时候发现和已经大于预期,那么4,5肯定也不行,这就是一种对搜索过程的优化。
回溯是递归的一种,或者说是通过递归这种代码结构来实现回溯这个目的。回溯法可以被认为是一个有过剪枝的DFS过程。
void dfs(int 当前状态)
{
if(当前状态为边界状态)
{
记录或输出
return;
}
for(i=0;i<n;i++) //横向遍历解答树所有子节点
{
//扩展出一个子状态。
修改了全局变量
if(子状态满足约束条件)
{
dfs(子状态)
}
恢复全局变量//回溯部分
}
}
3、最后就是DFS了,。那么dfs比起回溯有哪些优化的地方呢?
回溯搜索是深度优先搜索(DFS)的一种。对于某一个搜索树来说(搜索树是起记录路径和状态判断的作用),回溯和DFS,其主要的区别是,回溯法在求解过程中不保留完整的树结构,而深度优先搜索则记下完整的搜索树。
为了减少存储空间,在深度优先搜索中,用标志的方法记录访问过的状态,这种处理方法使得深度优先搜索法与回溯法没什么区别了。
BFS和DFS是相似。
BFS(显式用队列)
DFS(隐式用栈)(即递归)
当然,对于DFS,用递归可能会造成栈溢出,所以也可以更改为显示栈。
题外话,顺便把BFS的套路也写出来
将(起始)首节点加入队列: q.push(head);
标记首节点已经被访问: isvisited[head]=true;
以下自动反应: while(!q.empty())
{
int temp=q.front();
q.pop();
访问temp,并标记temp已被访问过,将temp的子相关节点加入队列
q.push(temp相关节点);
}
参考:https://www.cnblogs.com/smuxiaolei/p/7505391.html
https://blog.csdn.net/fightforyourdream/article/details/12866861