C++学习/复习补充记录 --- 图论(深搜,广搜)

图的存储

邻接表

邻接矩阵

深搜 与 广搜

数据结构与算法 | 深搜(DFS)与广搜(BFS)_深搜广搜算法-CSDN博客

深度优先搜索理论基础

深搜和广搜的区别

(通俗版)

广搜(bfs)是一圈一圈的搜索过程,

深搜(dfs)是一条路跑到黑然后再回溯。

  • dfs是可一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯)。
  • bfs是先把本节点所连接的所有节点遍历一遍,走到下一个节点的时候,再把连接节点的所有节点遍历一遍,搜索方向更像是广度,四面八方的搜索过程。
    二叉树的递归法,就是dfs。

二叉树的迭代法,就是bfs(广度优先搜索)。

所以dfs,bfs其实是基础搜索算法,也广泛应用与其他数据结构与算法中

深度优先搜索(Depth First Search)

深搜dfs关键就两点:

  • 搜索方向,是认准一个方向搜,直到碰壁之后再换方向
  • 换方向是撤销原路径,改为节点链接的下一个路径,回溯的过程。

因为dfs搜索可一个方向,并需要回溯,所以用递归的方式来实现是最方便的。

回溯链接:C++学习/复习补充记录 --- 递归、回溯_c++中回溯是啥-CSDN博客

深搜三部曲

1、确认递归函数,参数

2、确认终止条件

3、处理目前搜索节点出发的路径


深搜代码模板:

cpp 复制代码
//1、确认递归函数,参数
vector<vector<int>> result; // 保存符合条件的所有路径(存放结果组合的vector)
vector<int> path; // 起点到终点的路径(单个组合结果)
 
void dfs (图,目前搜索的节点)  {
    if (剪枝条件) return;//剪枝

    //2、确认终止条件
    if (终止条件) {
        result.push_back(path);//存放结果;
        return;
    }
 
    //3、处理目前搜索节点出发的路径
    for (选择:本层节点所连接的其他节点) {
        处理节点;(做选择)
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果(撤销选择)
    }
}

(回溯撤销处理结果其实就是:撤回一步,回到上一步重新走另一个方向。)

广度优先搜索(Breadth First Search)

1、应用场景

广搜的搜索方式就适合于解决两个点之间的最短路径问题。

因为广搜是从起点出发,以起始点为中心一圈一圈进行搜索,一旦遇到终点,记录之前走过的节点就是一条最短路

2、实现方式

用队列的话,就是保证每一圈都是一个方向去转,例如统一顺时针或者逆时针

因为队列是先进先出,加入元素和弹出元素的顺序是没有改变的。

如果用栈的话,就是第一圈顺时针遍历,第二圈逆时针遍历,第三圈有顺时针遍历

因为栈是先进后出,加入元素和弹出元素的顺序改变了。

广搜不需要注意 转圈搜索的顺序 !
广搜代码模板:

cpp 复制代码
int dir[4][2] = { 0, 1, 
				  1, 0, 
				 -1, 0, 
				  0, -1 }; // 表示四个方向
// grid 是地图,也就是一个二维数组
// visited标记访问过的节点,不要重复访问
// x,y 表示开始搜索节点的下标
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
	queue<pair<int, int>> que; // 定义队列
	que.push({ x, y }); // 起始节点加入队列
	visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点
	while (!que.empty()) { // 开始遍历队列里的元素
		pair<int, int> cur = que.front(); que.pop(); // 从队列取元素
		int curx = cur.first;
		int cury = cur.second; // 当前节点坐标
		for (int i = 0; i < 4; i++) { // 开始向当前节点的四个方向左右上下去遍历
			int nextx = curx + dir[i][0];
			int nexty = cury + dir[i][1]; // 获取周边四个方向的坐标
			if (nextx < 0 
				|| nextx >= grid.size() 
				|| nexty < 0 
				|| nexty >= grid[0].size()) continue;  // 坐标越界了,直接跳过
			if (!visited[nextx][nexty]) { // 如果节点没被访问过
				que.push({ nextx, nexty });  // 队列添加该节点为下一轮要遍历的节点
				visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
			}
		}
	}
}

(该模板针对的是如下图的四方格地图)

实际应用

输入数据的含义:

例一

cpp 复制代码
输入:graph = [[1,2],[3],[3],[]]

节点0可链接到的节点有:节点1,节点2;

节点1可链接到的节点有:节点3;

节点2可链接到的节点有:节点3;

节点3可链接到的节点有:无。

例二

cpp 复制代码
输入:graph = [[4,3,1],[3,2,4],[3],[4],[]]

节点0可链接到的节点有:节点4,节点3,节点1;

节点1可链接到的节点有:节点3,节点2,节点4;

节点2可链接到的节点有:节点3;

节点3可链接到的节点有:节点4;

节点4可链接到的节点有:无。

1.1 所有可能的路径 (深搜)

给你一个有 n 个节点的 有向无环图(DAG) ,请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序

graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。

cpp 复制代码
class Solution {
	vector<vector<int>> result;//符合条件的路径集合
	vector<int> path;//0节点到终点的路径
	void dfs(vector<vector<int>>& graph, int cur) {//cur为当前遍历到的节点
		if (cur == graph.size() - 1) {//要求从节点0到节点n-1的路径并输出,所以是 graph.size() - 1
			result.push_back(path);
			return;//已找到一条符合条件的路径
		}
		for (int i = 0; i < graph[cur].size(); i++) {//遍历当前节点可链接到的所有节点
			path.push_back(graph[cur][i]);//当前选择的链接节点尝试加入
			dfs(graph, graph[cur][i]);//加入下一层递归
			path.pop_back();//当前选择的链接节点走不通,不带上玩,腾出位置尝试另一个
		}
	}
public:
	vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
		path.push_back(0);//所有路径皆是从节点0出发
		dfs(graph, 0);//开始遍历
		return result;
	}
};

1.2

相关推荐
hahaha601643 分钟前
HLS高层次综合设计技巧--数组
开发语言·嵌入式硬件·算法·fpga开发
不会就选b1 小时前
算法日常・每日刷题--<贪心>10
算法
南京兴帝文化传媒有限公司1 小时前
本地生活服务商户GEO优化技术实践:AI大模型收录机制与地图POI权重算法拆解
大数据·人工智能·算法·生活·geo优化实操·csdn运营技巧·ai内容收录
汉克老师2 小时前
CSP-J 初赛(以满分为目标):第三十九课《数学与逻辑②——阶乘、排列数与组合数:公式到底从哪里来?》
c++·csp-j·小学生·学c++编程
水饺编程2 小时前
第5章,[Win32 章节] :在平面直角坐标系中描点
c语言·c++·windows·visual studio
linx2952 小时前
单元九 · 零基础路线图-第 7–9 周·类与 RAII
c语言·开发语言·数据结构·c++·嵌入式硬件·算法
布莱克6052 小时前
C++ 七大排序算法详解:选择、冒泡、插入、计数、堆、快速与归并排序
数据结构·c++·算法·排序算法
一只旭宝2 小时前
Python 与 C/C++ 内存模型对比总结
c语言·c++·python
心态还需努力呀2 小时前
把 Flameshot 编译进鸿蒙 PC:一次 Qt C++ 截图工具的源码级移植实战
c++·qt·harmonyos
shehuiyuelaiyuehao2 小时前
算法44,模拟算法,数青蛙
算法·哈希算法·散列表