代码随想录算法训练营第五十四天|Day54 图论

[复制链接]
发表于 2025-12-21 03:53:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
冗余毗连

  
https://www.programmercarl.com/kamacoder/0108.%E5%86%97%E4%BD%99%E8%BF%9E%E6%8E%A5.html

  思绪

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define MAX_N 1000
  4. // 并查集结构体
  5. typedef struct {
  6.     int parent[MAX_N + 1]; // 存储每个节点的父节点
  7.     int rank[MAX_N + 1];   // 存储每个节点的秩
  8. } UnionFind;
  9. // 初始化并查集
  10. void initUnionFind(UnionFind* uf, int n) {
  11.     for (int i = 1; i <= n; i++) {
  12.         uf->parent[i] = i; // 每个节点的父节点为自身
  13.         uf->rank[i] = 0;    // 初始秩为0
  14.     }
  15. }
  16. // 查找根节点
  17. int find(UnionFind* uf, int x) {
  18.     if (uf->parent[x] != x) {
  19.         // 路径压缩
  20.         uf->parent[x] = find(uf, uf->parent[x]);
  21.     }
  22.     return uf->parent[x];
  23. }
  24. // 合并两个集合
  25. int unionSets(UnionFind* uf, int x, int y) {
  26.     int rootX = find(uf, x);
  27.     int rootY = find(uf, y);
  28.     if (rootX == rootY) {
  29.         return 0; // 已经在同一个集合
  30.     }
  31.     // 按秩合并
  32.     if (uf->rank[rootX] < uf->rank[rootY]) {
  33.         uf->parent[rootX] = rootY;
  34.     } else if (uf->rank[rootX] > uf->rank[rootY]) {
  35.         uf->parent[rootY] = rootX;
  36.     } else {
  37.         uf->parent[rootY] = rootX;
  38.         uf->rank[rootX]++;
  39.     }
  40.     return 1; // 合并成功
  41. }
  42. int main() {
  43.     int n;
  44.     scanf("%d", &n); // 读取节点数量
  45.     UnionFind uf;
  46.     initUnionFind(&uf, n);
  47.     int redundancyEdge[2] = {0, 0}; // 冗余边的存储
  48.     for (int i = 0; i < n; i++) {
  49.         int u, v;
  50.         scanf("%d %d", &u, &v);
  51.         if (!unionSets(&uf, u, v)) {
  52.             // 如果这条边连接了已经在同一集合的两个节点,则这条边是冗余的
  53.             redundancyEdge[0] = u;
  54.             redundancyEdge[1] = v;
  55.         }
  56.     }
  57.     // 输出冗余边
  58.     printf("%d %d\n", redundancyEdge[0], redundancyEdge[1]);
  59.     return 0;
  60. }
复制代码
学习反思

  用于探求冗余边。并查集是一种用于维护聚集的数据结构,通过维护每个节点的父节点和秩来实现。步伐起首界说了一个UnionFind结构体,包罗两个数组,分别用于存储每个节点的父节点和秩。然后界说了初始化并查集的函数initUnionFind,并通过循环将每个节点的父节点设置为自身,并将秩初始化为0。接下来,界说了find函数,用于查找某个节点的根节点。该函数通过递归实现路径压缩,即在查找根节点的过程中将每个节点直接毗连到根节点,以镌汰查找的时间复杂度。然后,界说了unionSets函数,用于归并两个聚集。该函数起首找到两个节点的根节点,并判定它们是否雷同。假如根节点雷同,则阐明这两个节点已经在同一个聚集中,归并失败;否则,根据秩的巨细决定将哪个聚集的根节点毗连到另一个聚集的根节点,并更新秩。在主函数中,起首读取节点的数目n。然后初始化并查集,界说了一个数组redundancyEdge用于存储冗余边的两个节点。接着通过一个循环读取每条边的两个节点u和v,并通过调用unionSets函数将它们归并。假如归并失败,则阐明这条边是冗余的,更新redundancyEdge数组。末了,输出redundancyEdge数组中存储的冗余的两个节点。该步伐的时间复杂度为O(n*logn),此中n为节点的数目。
  冗余毗连II

  
https://www.programmercarl.com/kamacoder/0109.%E5%86%97%E4%BD%99%E8%BF%9E%E6%8E%A5II.html

  思绪

  1. #include <stdio.h>
  2. #define MAX_N 1001
  3. int main() {
  4.     int n;
  5.     scanf("%d", &n); // 读取节点和边的数量
  6.     int indegree[MAX_N] = {0}; // 每个节点的入度
  7.     int parent[MAX_N] = {0}; // 记录每个节点的父节点
  8.     int lastRedundantEdge[2] = {0, 0}; // 存储最后找到的冗余边(s,t)
  9.     for (int i = 0; i < n; i++) {
  10.         int s, t;
  11.         scanf("%d %d", &s, &t);
  12.         
  13.         // 增加t的入度
  14.         indegree[t]++;
  15.         
  16.         // 记录t的父节点是s
  17.         parent[t] = s;
  18.         // 如果t的入度超过1,则更新冗余边
  19.         if (indegree[t] > 1) {
  20.             lastRedundantEdge[0] = s; // 冗余边的起点
  21.             lastRedundantEdge[1] = t; // 冗余边的终点
  22.         }
  23.     }
  24.     // 输出最后一个找到的冗余边
  25.     printf("%d %d\n", lastRedundantEdge[0], lastRedundantEdge[1]);
  26.     return 0;
  27. }
复制代码
学习反思

  用来探求有向图中的末了一条冗余边的。冗余边指的是参加这条边后,有向图中会形成一个环。算法的思绪是通过纪录每个节点的入度和其父节点,然后遍历每条边,假如某个节点的入度凌驾1,则阐明存在冗余边。末了输出末了找到的冗余边的出发点和尽头。
  这段代码的时间复杂度为O(n),此中n为节点和边的数目。由于必要遍历一遍全部的边来纪录每个节点的入度和其父节点,并判定是否存在冗余边。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表