zoukankan      html  css  js  c++  java
  • 【模板】强连通分量和tarjan算法

      看了好久才终于明白了这个算法。。复杂度是O(n+m)。

      我觉得这个算法不是很好理解,但是看懂了以后还是觉得听巧妙的。

      下面给出模板代码和三组简单数据帮助理解。

      代码如下:

     1 #include <stdio.h>
     2 #include <stack>
     3 #include <algorithm>
     4 #include <string.h>
     5 #include <vector>
     6 using namespace std;
     7 
     8 const int N = 100+5;
     9 
    10 stack<int> S;
    11 int scc_cnt;  //强连通分量的个数
    12 int dfs_clock;    //访问到该节点的时间戳
    13 int belong[N];  //belong[i]表示i节点所属于第几个强连通分量
    14 int dfn[N];     //表示第i个节点被访问的时间
    15 int low[N];    //表示第i个节点的子节点所能访问到的最小的dfn值
    16 vector<int> G[N];
    17 
    18 void dfs(int u)
    19 {
    20     dfn[u] = low[u] = ++dfs_clock;
    21     S.push(u);
    22     for(int i=0;i<G[u].size();i++)
    23     {
    24         int v = G[u][i];
    25         if(!dfn[v])
    26         {
    27             dfs(v);
    28             low[u] = min(low[u],low[v]);
    29         }
    30         else if(!belong[v]) //这句话等价于v在栈内
    31         {
    32             low[u] = min(low[u],low[v]);
    33             //low[u] = min(low[u],dfn[v]);
    34             //上面两种写法似乎都是没有问题的,但是如果仔细斟酌第三组数据和low的定义的话
    35             //似乎是上面的写法更好,这里不敢确定,留个疑问。
    36         }
    37     }
    38     if(low[u]==dfn[u])
    39     {
    40         scc_cnt++;
    41         for(;;)
    42         {
    43             //因为元素x只有在出栈了以后才被赋予归属,所以这就是上面等价的原因
    44             //同时,因为所有元素都有归属,则栈S中最后没有元素,因此不需要清空S
    45             int x = S.top();S.pop();
    46             belong[x] = scc_cnt;
    47             if(x==u) break;
    48         }
    49     }
    50 }
    51 
    52 void scc(int n)
    53 {
    54     memset(dfn,0,sizeof(dfn));
    55     memset(belong,0,sizeof(belong));
    56     dfs_clock = scc_cnt = 0;
    57     for(int i=0;i<n;i++) //注意这里是0~n-1!
    58     {
    59         if(!dfn[i]) dfs(i);
    60     }
    61 }
    62 
    63 int main()
    64 {
    65     int n,m;
    66     scanf("%d%d",&n,&m);
    67     for(int i=0;i<m;i++)
    68     {
    69         int a,b;
    70         scanf("%d%d",&a,&b);
    71         G[a].push_back(b);
    72     }
    73     scc(n);
    74     puts("");
    75     for(int i=0;i<n;i++) printf("%d %d %d %d
    ",i,belong[i],dfn[i],low[i]);
    76     printf("%d
    ",scc_cnt);
    77     return 0;
    78 }

      三组数据如下:

    6 6
    0 1
    1 2
    2 5
    0 3
    3 4
    4 5
     
    4 4
    0 1
    1 2
    2 3 
    3 0
    
    6 8
    0 1
    0 2
    2 3 
    1 3
    3 0
    2 4
    4 5
    3 5
  • 相关阅读:
    smokeping一键安装脚本
    IIS与Apache禁止IP地址直接访问网站
    linux 常用命令
    ELK安装
    MySQL5.7安装
    Centos7 动态创建文件系统
    python学习第十六天 内置函数2,匿名函数
    python学习第十五天 内置函数1
    python学习第十四天 生成器函数进阶 生成器表达式 各种推导式
    python学习第十三天 迭代器 生成器
  • 原文地址:https://www.cnblogs.com/zzyDS/p/5624711.html
Copyright © 2011-2022 走看看