代码随想录day58图论8
文章目录
- 拓扑排序
- dijkstra(朴素版)
拓扑排序
卡恩算法(Kahn’s Algorithm)思路:
入度数组:
首先计算图中每个节点的入度(即指向该节点的边的数量)。如果一个节点的入度为0,表示没有任何其他节点指向它,意味着它可以被排在拓扑排序的最前面。
BFS队列:
使用一个队列(Queue)来存放所有入度为0的节点,因为它们可以开始拓扑排序。我们从这些节点开始,逐步处理。
遍历节点:
从队列中取出一个节点,将其加入拓扑排序的结果列表中。
对于每一个从当前节点指向的邻接节点,将它们的入度减1。
如果邻接节点的入度减为0,则将该节点加入队列,因为它现在可以加入拓扑排序。
检查是否有环:
如果最终的拓扑排序结果包含所有节点,说明图是有向无环图(DAG),并且找到了合法的拓扑排序。
如果有节点的入度始终不为0,说明图中存在环,无法进行拓扑排序。
题目链接
文章讲解
#include <bits/stdc++.h>
using namespace std;int main() {int v, e; // v为节点数,e为边数cin >> v >> e; // 输入节点数和边数// 入度数组,记录每个节点的入度(指向该节点的边的数量)vector<int> indgree(v, 0);// 队列,用来存储入度为0的节点queue<int> q;// 存储拓扑排序的结果vector<int> ans;// 邻接表,用来存储每个节点指向的节点unordered_map<int, vector<int>> m;// 输入所有的边,更新入度数组和邻接表while (e--) {int x, y;cin >> x >> y; // 输入边的两个端点x和yindgree[y]++; // 节点y的入度加1m[x].push_back(y); // 将y加入x的邻接表中,表示有边x->y}// 将所有入度为0的节点加入队列for (int i = 0; i < v; i++) {if (indgree[i] == 0) q.push(i);}// 使用BFS处理入度为0的节点while (!q.empty()) {int cur = q.front(); // 获取队列中的节点q.pop(); // 从队列中移除该节点ans.push_back(cur); // 将当前节点加入拓扑排序结果// 遍历当前节点指向的所有邻接节点auto k = m[cur]; // 获取当前节点的邻接节点for (int j = 0; j < k.size(); j++) {indgree[k[j]]--; // 当前邻接节点的入度减1if (indgree[k[j]] == 0) q.push(k[j]); // 如果该邻接节点入度为0,加入队列}}// 判断是否所有节点都被处理过if (ans.size() == v) {// 如果拓扑排序成功,输出排序结果for (int i = 0; i < ans.size(); i++) {if (i != 0) cout << " " << ans[i]; // 不是第一个节点时,输出空格分隔else cout << ans[i]; // 第一个节点直接输出}} else {// 如果拓扑排序失败,说明图中有环,输出-1cout << -1;}}
dijkstra(朴素版)
以下为dijkstra 三部曲
1、选源点到哪个节点近且该节点未被访问过
源点距离源点最近,距离为0,且未被访问。
2、该最近节点被标记访问过
标记源点访问过
3、更新非访问节点到源点的距离(即更新minDist数组)
题目链接
文章讲解
#include <bits/stdc++.h>
using namespace std;int main() {int n, m;cin >> n >> m; // 输入节点数n和边数m// 初始化图的邻接矩阵,大小为 (n+1) x (n+1),初始值设为 INT_MAXvector<vector<int>> grid(n + 1, vector<int>(n + 1, INT_MAX));// 初始化访问标记数组,所有节点初始为未访问vector<bool> visited(n + 1, false);// 初始化最短路径数组,所有节点的最短路径初始化为 INT_MAXvector<int> mindist(n + 1, INT_MAX);// 读取 m 条边的输入,并更新邻接矩阵 grid[x][y] 为边的权重while (m--) {int x, y, z;cin >> x >> y >> z;grid[x][y] = z; // x 到 y 的边权重为 z}// 起点 1 到自己的最短距离为 0mindist[1] = 0;int cur = 1; // 初始时从节点 1 开始// 执行 Dijkstra 算法,遍历每个节点for (int i = 1; i <= n; i++) {int minval = INT_MAX;// 在未访问的节点中,找出最短路径的节点 curfor (int j = 1; j <= n; j++) {if (!visited[j] && minval > mindist[j]) {cur = j; // 更新当前节点为距离最小的节点minval = mindist[j]; // 更新最小的距离}}// 将当前节点标记为已访问visited[cur] = true;// 更新当前节点 cur 的邻接节点的最短路径for (int j = 1; j <= n; j++) {// 如果节点 j 未访问,并且存在从 cur 到 j 的边,且通过 cur 更新后的路径更短if (!visited[j] && grid[cur][j] != INT_MAX && mindist[cur] + grid[cur][j] < mindist[j]) {mindist[j] = mindist[cur] + grid[cur][j]; // 更新最短路径}}}// 如果目标节点 n 的最短路径仍为 INT_MAX,表示无法到达目标节点if (mindist[n] == INT_MAX)cout << -1; // 输出 -1,表示从节点 1 无法到达节点 nelsecout << mindist[n]; // 输出从节点 1 到节点 n 的最短路径}