• 图的强连通问题


    图的强连通问题

    ——求强连通分量个数,找出每个最大强连通子图。

    三种算法,Tarjan、Kosaraju、Garbow。先说Tarjan。

    Tarjan

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<stack>
     6 using namespace std;
     7 const int maxv= 110;
     8 const int maxe= 5010;  //可能的最大值
     9 
    10 struct ENode
    11 {
    12     int to;
    13     int Next;
    14 };
    15 ENode edegs[maxe];
    16 int Head[maxv], tnt;
    17 void init()
    18 {
    19     memset(Head, -1, sizeof(Head));
    20     tnt= -1;
    21 }
    22 void Add_ENode (int a, int b)
    23 {
    24     ++ tnt;
    25     edegs[tnt].to= b;
    26     edegs[tnt].Next= Head[a];
    27     Head[a]= tnt;
    28 }
    29 
    30 int m;
    31 int dfn[maxv];  //深度优先搜索中顶点被访问的时间
    32 int low[maxv];  //顶点v 和它的邻接点中low[]的最小值
    33 int temp[maxv];  //判断节点是否已被访问过(0-未访问 1-已访问未删除 2-已访问已删除)
    34 int Stack[maxv];  //手动栈
    35 int TarBfs (int v, int lay, int &scc_num)
    36 {
    37     /*v: 新加入的点; lay: 时间戳; scc_num: 记录强连通分量的数量*/
    38 
    39     /*第2步:初始化dfn[v]和low[v]*/
    40     temp[v]= 1;
    41     low[v]= lay;
    42     dfn[v]= lay;
    43     Stack[++ m]= v;
    44     for (int k= Head[v]; k!= -1; k= edegs[k].Next)
    45     {
    46         /*对于v 的所有邻接节点u:*/
    47         int u= edegs[k].to;
    48         if (temp[u]== 0)
    49         {
    50             /*第2-1步:如果没有访问过,则跳转执行第2步,同时维护low[v]*/
    51             TarBfs(u, ++ lay, scc_num);
    52         }
    53         if (temp[u]== 1)
    54         {
    55             /*第2-2步:如果访问过,但没有删除,维护low[v]*/
    56             low[v]= min(low[v], low[u]);
    57         }
    58     }
    59     if (dfn[v]== low[v])
    60     {
    61         /*如果low[v]== dfn[v],则当前节点是一个强连通分量的根,
    62         那么输出相应的强连通分量。*/
    63         ++ scc_num;
    64         do
    65         {
    66             low[Stack[m]]= scc_num;
    67             temp[Stack[m]]= 2;  //已删除的节点temp更新为2
    68         }while (Stack[m --]!= v);
    69     }
    70     return 0;
    71 }
    72 
    73 int Tarjan(int n)
    74 {
    75     int scc_num= 0, lay= 1;
    76     m= 0;
    77     memset(temp, 0, sizeof(temp));
    78     memset(low, 0, sizeof(low));
    79     for (int i= 1; i<= n; i ++)
    80     {
    81         if (temp[i]== 0)
    82         {
    83             /*第1步:找一个没有被访问过的节点v,否则算法结束*/
    84             TarBfs(i, lay, scc_num);
    85         }
    86     }
    87     /*返回强连通分量的个数*/
    88     return scc_num;
    89 }
    90 
    91 int main()
    92 {
    93     int n;
    94     /*建图*/
    95     int ans= Tarjan(n);
    96     return 0;
    97 }
    只求个数

    思路:

      如果对于原图进行深度优先搜索,由强连通分量定义可知,任何一个强连通分量是原图的深度优先搜索树的子树。那么,只要确定每个极大强连通子图(强连通分量子树)的根,然后根据这些根从数的最底层开始,一个一个地取出强连通分量即可。

      对于确定强连通分量的根,这里维护两个数组,一个是dfn[ ],一个是low[ ],其中dfn[v ] 表示顶点v 被访问的时间,low[v ]为与顶点v 邻接的未删除的顶点u 的low[u ]与low[v ]的最小值(low[v ]初始化为dfn[v ] )。如果发现一个点,low[v ]== dfn[v ] ,则该点就是一个强连通分量的根。

    伪代码:

    1.找一个没有被访问过的节点v,否则算法结束

    2.初始化dfn[v]和low[v]。对于v 的所有邻接节点u:

    ①如果没有访问过,则跳转执行第2步,同时维护low[v];

    ②如果访问过,但没有删除,维护low[v];

    如果low[v]== dfn[v],则当前节点是一个强连通分量的根,那么输出相应的强连通分量。

  • 相关阅读:
    VSTO开发指南(VB2013版) 第四章 Excel编程
    VSTO开发指南(VB2013版) 第三章 Excel编程
    VSTO开发指南(VB2013版) 第二章 Office解决方案介绍
    VSTO开发指南(VB2013版) 第一章 Office对象模型
    打印预览
    打印
    工具函数
    开始使用
    模版对应信息
    解决PLSQL或者sqlplus连接oracle慢的方法
  • 原文地址:https://www.cnblogs.com/Amaris-diana/p/11254066.html
Copyright © 2020-2023  润新知