当前位置: 首页 > news >正文

代码随想录算法训练营第四十一天|图论基础、深度优先搜索理论基础、98. 所有可达路径、797. 所有可能的路径

图论基础

图的种类:有向图 和 无向图,加权有向图, 加权无向图

无向图中有几条边连接该节点,该节点就有几度。

在有向图中,每个节点有出度和入度。出度:从该节点出发的边的个数。入度:指向该节点边的个数。

图的遍历方式:

  • 深度优先搜索(dfs)
  • 广度优先搜索(bfs)

 深度优先搜索(DFS)、广度优先搜索(BFS)、并查集、拓扑排序、最小生成树系列、最短路算法系列...

深度优先搜索理论基础

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

DFS(深度优先搜索):

往一个方向搜索,不到黄河不回头。
从1到6的第一条路径如下:

此时我们找到了节点6,(遇到黄河了,是不是应该回头了),那么应该再去搜索其他方向了。 

路径2撤销了,改变了方向,走路径3(红色线), 接着也找到终点6。 那么撤销路径2,改为路径3,在dfs中其实就是回溯的过程(这一点很重要,很多录友不理解dfs代码中回溯是用来干什么的)

又找到了一条从节点1到节点6的路径,又到黄河了,此时再回头,下图图四中,路径4撤销(回溯的过程),改为路径5。

又找到了一条从节点1到节点6的路径,又到黄河了,此时再回头,下图图五,路径6撤销(回溯的过程),改为路径7,路径8 和 路径7,路径9, 结果发现死路一条,都走到了自己走过的节点。

那么节点2所连接路径和节点3所链接的路径 都走过了,撤销路径只能向上回退,去选择撤销当初节点4的选择,也就是撤销路径5,改为路径10 。 如图图六:

其他节点的过程省略,总体来说的两个步骤就是:

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

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

void dfs(参数) {处理节点dfs(图,选择的节点); // 递归回溯,撤销处理结果
}

回溯算法,其实就是dfs的过程:

void dfs(参数) {if (终止条件) {存放结果;return;}for (选择:本节点所连接的其他节点) {处理节点;dfs(图,选择的节点); // 递归回溯,撤销处理结果}
}

深搜三部曲:

1. 确定递归函数;2. 确认终止条件; 3. 处理目前搜索节点出发的路径

98. 所有可达路径

实现这两个图的存储方式:邻接矩阵 邻接表

邻接矩阵:

vector<vector<int>> graph(n + 1, vector<int>(n + 1, 0));
// 输入m个边,构造方式如下:
while (m--) {cin >> s >> t;// 使用邻接矩阵 ,1 表示 节点s 指向 节点tgraph[s][t] = 1;
}

邻接表: 数组 + 链表的方式来表示。邻接表是从边的数量来表示图,有多少边 才会申请对应大小的链表。

// 节点编号从1到n,所以申请 n+1 这么大的数组
vector<list<int>> graph(n + 1); // 邻接表,list为C++里的链表
// 输入m个边,构造方式如下:
while (m--) {cin >> s >> t;// 使用邻接表 ,表示 s -> t 是相连的graph[s].push_back(t);
}

1. 确认递归函数:

vector<vector<int>> result; // 收集符合条件的路径
vector<int> path; // 0节点到终点的路径
// x:目前遍历的节点
// graph:存当前的图
// n:终点
void dfs (const vector<vector<int>>& graph, int x, int n) {

2. 确认终止条件:

当目前遍历的节点 为 最后一个节点 n 的时候 就找到了一条 从出发点到终止点的路径。

// 当前遍历的节点x 到达节点n 
if (x == n) { // 找到符合条件的一条路径result.push_back(path);return;
}

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

for(int i=1; i<=n; i++){if(graph[x][i] == 1) {path.push_back(i);dfs(graph, i, n);path.pop_back(i);}
}

所以本题使用ACM模式写出来就是:

#include <iostream>
#include <vector>
#include <list>
using namespace std;
vector<vector<int>> result;
vector<int> path;//void dfs(const vector<vector<int>>& graph, int x, int n){void dfs(const vector<list<int>>& graph, int x, int n){//当前遍历的节点x到达节点nif(x==n){result.push_back(path);return;}// for(int i=1; i<=n; i++){//     if(graph[x][i]==1){ //找到x链接的节点//         path.push_back(i);//         dfs(graph, i, n);//         path.pop_back();//     }// }for(int i:graph[x]){path.push_back(i);dfs(graph, i, n);path.pop_back();}
}
int main(){int n, m, s, t;cin>>n>>m;//vector<vector<int>> graph(n+1, vector<int>(n+1, 0));vector<list<int>> graph(n+1);while(m--){cin>>s>>t;//graph[s][t] = 1;graph[s].push_back(t);}path.push_back(1);//无论什么路径已经是从0节点出发dfs(graph, 1, n);if(result.size()==0) cout<<-1<<endl;for(const vector<int>&pa : result){for(int i=0; i<pa.size()-1; i++){cout<<pa[i]<<" ";}cout<<pa[pa.size()-1]<<endl;}
}

797. 所有可能的路径

class Solution {
public:vector<vector<int>> result;vector<int> path;void dfs(vector<vector<int>>& graph, int x, int n){if(x==n){result.push_back(path);return;}// for(int i=1; i<=n; i++){//     if(graph[x][i]==1){//         path.push_back(i);//         dfs(graph, i, n);//         path.pop_back();//     }// }for (auto& y : graph[x]) {path.push_back(y);dfs(graph, y, n);path.pop_back();}}vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {path.push_back(0);dfs(graph, 0, graph.size()-1);return result;}
};
http://www.lryc.cn/news/423459.html

相关文章:

  • STM32学习笔记09-SPI通信
  • 树------二叉树
  • 如何对加密后的数据进行模糊查询(面试题)
  • 【MYSQL】当前读和快照读
  • C语言-使用数组法,指针法实现将一个5X5的矩阵中最大的元素放在中心,四个角分别放四个最小的元素(顺序为从左到右,从上到下,从小到大存放),写一函数实现之。
  • Android gradle 构建
  • vulnhub系列:devguru
  • Robot Operating System——高质量图像传输
  • NLP_情感分类_预训练加微调方案
  • 全网最适合入门的面向对象编程教程:36 Python的内置数据类型-字典
  • DataWind看板绘制案例
  • Golang | Leetcode Golang题解之第335题路径交叉
  • C# 在Word中插入或删除分节符
  • 基于STM32+Qt设计的无人超市收银系统(206)
  • 开源免费的表单收集系统TDuck
  • Python 生成器、迭代器、可迭代对象 以及应用场景
  • 马斯克对欧盟的反应
  • uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载
  • Elasticsearch 8 RAG 技术分享
  • 根据字典值回显,有颜色的
  • 多台PC网络ADB连接同一台RK3399 Android7.1.2设备
  • 前端黑科技:使用 JavaScript 实现网页扫码功能
  • 【人工智能】全景解析:【机器学习】【深度学习】从基础理论到应用前景的【深度探索】
  • MySQL与PostgreSQL语法区别
  • vue2+OpenLayers 天地图上凸显出当前地理位置区域(4)
  • 基于Python、Django开发Web计算器
  • 高性能并行计算面试-核心概念-问题理解
  • java-activiti笔记
  • Layui——隐藏表单项后不再进行验证
  • Github Copilot 使用技巧