无向图的桥

x33g5p2x  于2022-07-04 转载在 其他  
字(1.5k)|赞(0)|评价(0)|浏览(269)

一 点睛

时间戳:dfn[u] 表示节点 u 深度优先遍历的序号。

追溯点:low[u]表示节点u或u的子孙能通过非父子追溯到dfn最小节点的序号,即回到最早的过去。

二 举例

初始时,dfn[u]=low[u],如果该节点的邻节点未被访问,则一直进行深度优先遍历,1-2-3-5-6-4,此时 4 的邻接点 1 已被访问,且 1 不是 4 的父节点,4 的父节点是6(深度优先搜索树上的父节点)。

节点 4 能回到最早的节点是节点1(dfn=1),因此low[4]=min(low[4],dfn[1])=1,返回时,更新low[6]=min(low[6],low[4])=1。更新路径上所有祖先节点的 low 值,因为子孙能回到的追溯点,其祖先也能回到。

三 无向图的桥

桥判定法则:无向边 x-y 是桥,当且仅当搜索树上存在一个节点 y,满足 low[y] > dfn[x]。

也就是说,如果孩子的 low 值比自己大,则从该节点到这个孩子的边为桥。在上图中,边5-7中,5的子节点为7,满足 low[7]>dfn[5],因此 5-7 为桥。

四 代码

  1. package graph.tarjanbridge;
  2. import java.util.Arrays;
  3. import java.util.Scanner;
  4. public class TarjanBridge {
  5. static int SIZE = 100010;
  6. static int head[] = new int[SIZE], to[] = new int[SIZE << 1], next[] = new int[SIZE << 1];
  7. static int cnt = 0;
  8. static void addEdge(int x, int y) {
  9. to[cnt] = y;
  10. next[cnt] = head[x];
  11. head[x] = cnt++;
  12. to[cnt] = x;
  13. next[cnt] = head[y];
  14. head[y] = cnt++;
  15. }
  16. static int dfn[] = new int[SIZE], low[] = new int[SIZE];
  17. static int index;
  18. static boolean bridge[] = new boolean[SIZE << 1];
  19. static void tarjan(int x, int edge) {
  20. dfn[x] = low[x] = ++index;
  21. for (int i = head[x]; i >= 0; i = next[i]) {
  22. int y = to[i];
  23. if (dfn[y] == 0) {
  24. tarjan(y, i);
  25. low[x] = Math.min(low[x], low[y]);
  26. if (dfn[x] < low[y])
  27. bridge[i] = bridge[i ^ 1] = true;
  28. } else if (i != (edge ^ 1))
  29. low[x] = Math.min(low[x], dfn[y]);
  30. }
  31. }
  32. static void init() {
  33. Arrays.fill(head, -1);
  34. cnt = 0;
  35. }
  36. static int n, m;
  37. public static void main(String[] args) {
  38. Scanner sc = new Scanner(System.in);
  39. n = sc.nextInt();
  40. m = sc.nextInt();
  41. init();
  42. for (int i = 0; i < m; i++)
  43. addEdge(sc.nextInt(), sc.nextInt());
  44. for (int i = 1; i <= n; i++)
  45. if (dfn[i] == 0)
  46. tarjan(i, -1);
  47. for (int i = 1; i < cnt; i += 2)
  48. if (bridge[i])
  49. System.out.println(to[i ^ 1] + " " + to[i]);
  50. }
  51. }

五 测试

相关文章