• 有向图的强连通分量


    一 算法步骤

    1 深度优先遍历节点,在第一次访问节点x时,将 x 入栈,且 dfn[x]=low[x]=++num

    2 遍历 x 的所有邻接点y。

    若 y 没被访问,则递归访问 y,返回时更新 low[x]=min(low[x],low[y])

    若 y 已被访问且在栈中,则令 low[x]=min(low[x],dfn[y])

    3 在x回溯之前,如果判断 low[x]=dfn[x],则从栈中不断弹出节点,直到 x 出栈时停止。弹出的节点就是一个连通分量。

    二 举例

    1 从节点 1 出发进行深度优先搜索,dfn[1]=low[1]=1,1入栈;

    2 遍历1的所有邻接点

    2 没有被访问,递归访问 2,2 入栈,返回时,更新 dfn[2]=low[2]=2。

    3 回溯时,因为 dfn[2]=low[2],2 出栈,得到强连通分量2。

    4 回溯到 1 后,继续访问1的下一个邻接点3,接着访问 3-4-5,5 的邻接点 1 的已经访问,且 1 在栈中,更新low[5]=min(low[5],dfn[1])=1,回溯时更新 low[4]=min(low[4],low[5])=1, low[3]=min(low[3],low[4])=1,low[1]=min(low[1],low[3])=1.节点 1 的所有邻接点都已访问完毕,因为 dfn[1]=low[1],所以开始出栈,直到遇到1,得到强连通分量 5 4 2 1。

    三 代码

    1. package graph.tarjanscc;
    2. import java.util.Scanner;
    3. import java.util.Stack;
    4. public class TarjanSCC {
    5. static final int maxn = 1000 + 5;
    6. static int n;
    7. static int m;
    8. static int head[];
    9. static int cnt;
    10. static int root;
    11. static int low[];
    12. static int dfn[];
    13. static int num;
    14. static Edge e[] = new Edge[maxn << 1];
    15. static Stack<Integer> s = new Stack<>();
    16. static boolean ins[] = new boolean[maxn];
    17. static {
    18. for (int i = 0; i < e.length; i++) {
    19. e[i] = new Edge();
    20. }
    21. }
    22. static void add(int u, int v) { // 添加一条边u--v
    23. e[++cnt].next = head[u];
    24. e[cnt].to = v;
    25. head[u] = cnt;
    26. }
    27. static void tarjan(int u) { // 求强连通分量
    28. low[u] = dfn[u] = ++num;
    29. System.out.println("low[" + "]=" + low[u] + "\tdfn[" + u + "]=" + dfn[u]);
    30. ins[u] = true;
    31. s.push(u);
    32. for (int i = head[u]; i != 0; i = e[i].next) {
    33. int v = e[i].to;
    34. if (dfn[v] == 0) {
    35. tarjan(v);
    36. low[u] = Math.min(low[u], low[v]);
    37. System.out.println("update1:low[" + u + "]=" + low[u]);
    38. } else if (ins[v]) {
    39. low[u] = Math.min(low[u], dfn[v]);
    40. System.out.println("update2:low[" + u + "]=" + low[u]);
    41. }
    42. }
    43. if (low[u] == dfn[u]) {
    44. int v;
    45. System.out.println("强连通分量:");
    46. do {
    47. v = s.peek();
    48. s.pop();
    49. System.out.print(v + " ");
    50. ins[v] = false;
    51. } while (v != u);
    52. System.out.println();
    53. }
    54. }
    55. static void init() {
    56. head = new int[maxn];
    57. low = new int[maxn];
    58. dfn = new int[maxn];
    59. ins = new boolean[maxn];
    60. cnt = num = 0;
    61. }
    62. public static void main(String[] args) {
    63. Scanner scanner = new Scanner(System.in);
    64. n = scanner.nextInt();
    65. m = scanner.nextInt();
    66. init();
    67. int u, v;
    68. while (m-- > 0) {
    69. u = scanner.nextInt();
    70. v = scanner.nextInt();
    71. add(u, v);
    72. }
    73. for (int i = 1; i <= n; i++)
    74. if (dfn[i] == 0) {
    75. tarjan(i);
    76. }
    77. }
    78. }
    79. class Edge {
    80. int to;
    81. int next;
    82. }

    四 测试

    绿色为输入,白色为输出。

  • 相关阅读:
    用SuperMap版leaflet框架对SuperMap iServer发布的3个数据集进行叠加分析
    打造高效的私密论坛网站:Cpolar内网穿透+HadSky轻量级搭建指南
    python编程:创建 SQLite 数据库和表的图形用户界面应用程序
    sql server导入表格出现错误
    kafka安装部署,和基本操作
    SpringBoot程序的打包与运行
    C++初阶(命名空间+缺省参数+const总结+引用总结+内联函数+auto关键字)
    【光学】基于matlab GUI光栅条纹投影生成【含Matlab源码 2118期】
    java 数据结构 优先级队列(PriorityQueue)
    Redis 的特点及命令大全
  • 原文地址:https://blog.csdn.net/chengqiuming/article/details/125573122