递归 回溯 DFS的区别

写了很多题以后,突然乱掉了,尤其是递归和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

下面给出一个基于递归回溯算法的C++代码实现: ```c++ #include <iostream> #include <vector> #include <stack> #include <ctime> #include <cstdlib> using namespace std; const int N = 1010; int n, m; // 迷宫的行数和列数 int maze[N][N]; // 迷宫地图 int vis[N][N]; // 标记是否访问过某个点 // 定义四个方向 int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1}; // 判断某个点是否在迷宫内 bool inMaze(int x, int y) { return x >= 0 && x < n && y >= 0 && y < m; } // 随机生成迷宫地图 void generateMaze() { srand(time(0)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { maze[i][j] = rand() % 2; // 随机生成0或1 } } maze[0][0] = maze[n - 1][m - 1] = 0; // 迷宫入口和出口不能是障碍物 } // 递归回溯求解迷宫 bool dfs(int x, int y) { if (x == n - 1 && y == m - 1) return true; // 找到出口 vis[x][y] = 1; // 标记当前点为已访问 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (inMaze(nx, ny) && maze[nx][ny] == 0 && !vis[nx][ny]) { // 判断是否可以走到下一个点 if (dfs(nx, ny)) return true; // 递归搜索下一个点 } } return false; // 找不到出口 } int main() { cin >> n >> m; generateMaze(); cout << "迷宫地图:" << endl; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << maze[i][j] << " "; } cout << endl; } cout << "是否有解:" << (dfs(0, 0) ? "是" : "否") << endl; return 0; } ``` 在这个代码中,我们先随机生成一个迷宫地图,然后从入口开始使用递归回溯算法搜索迷宫。在搜索过程中,我们使用一个二维数组 `vis` 记录每个点是否访问过,确保不会重复访问同一个点。如果找到了出口,则返回 true;否则,返回 false。最后输出是否有解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值