• 有向图连通分量SCC


    在无向图中,如果从顶点vi到顶点vj有路径,则称vi和vj连通。如果图中任意两个顶点之间都连通,则称该图为连通图,否则,称该图为非连通图,则其中的极大连通子图称为连通分量,这里所谓的极大是指子图中包含的顶点个数极大。
    直观地说,极大就是不能再大,或者说再大也不能超过自己。因此,极大连通子图就是:
      设
      1) S为G的子图,S连通,
      2) 如果有S'也是G的连通子图,且S是S'的子图,可推出S = S',
      则称S是G的极大连通子图。
      极小连通子图正好相反,极小就是不能再小,再多小一点就会不连通或点不足。因此,极小连通子图就是:
      设
      1) S为G的子图,S连通,
      2) 如果有S'也是G的连通子图,S'包含G的所有顶点,且S'是S的子图,可推出S' = S,
      则称S是G的级小连通子图。
      注:这个定义和pinejeely给出的等价。这里给出的定义比较容易验证。
    在有向图中,如果对于每一对顶点vi和vj,从vi到vj和从vj到vi都有路径,则称该图为强连通图;否则,将其中的极大强连通子图称为强连通分量。
     

    Kosaraju算法:先dfs,得到最后完成时间f,再求反图,按f递减的方向对反图再dfs一次。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <algorithm>
      4 #include <iomanip>
      5 #include <set>
      6 #include <map>
      7 #include <vector>
      8 #include <queue>
      9 using namespace std;
     10 #define N 1000
     11 int head[N], headt[N], cnt;
     12 struct node 
     13 {
     14     int next, to;
     15 }edge[N * 2], edget[N * 2];
     16 
     17 void addedge(int from, int to)//G_T
     18 {
     19     cnt++;
     20     edge[cnt].next = head[from];
     21     edge[cnt].to = to;
     22     head[from] = cnt;
     23     //得到反图
     24     edget[cnt].next = headt[to];
     25     edget[cnt].to = from;
     26     headt[to] = cnt;
     27 }
     28 int f[N];//finishtime
     29 int d[N];//discovertime
     30 int color[N];//init 0 denote white; 1 denote gray discover; 2 denote black finish 
     31 int time; 
     32 int belong[N];//which scc
     33 int cur;//current scc
     34 void dfs_visit(int x)
     35 {
     36     color[x] = 1;
     37     d[x] = ++time;
     38     int i, j;
     39     for (i = head[x]; i; i = edge[i].next)
     40     {
     41         j = edge[i].to;
     42         if (!color[j])
     43         {
     44             dfs_visit(j);
     45         }
     46     }
     47     //color[x] = 2;
     48     f[x] = ++time;
     49 }
     50 
     51 void dfs_visit_t(int x)
     52 {
     53     color[x] = 1;
     54     //d[x] = ++time;
     55     int i, j;
     56     for (i = headt[x]; i; i = edget[i].next)
     57     {
     58         j = edget[i].to;
     59         if (!color[j])
     60         {
     61             dfs_visit_t(j);
     62         }
     63     }
     64     //color[x] = 2;
     65     //f[x] = ++time;
     66     belong[x] = cur;
     67 }
     68 
     69 bool cmp(const int &a, const int &b)
     70 {
     71     return a > b;
     72 }
     73 
     74 map<int, int, greater<int> > mp;//使用map对f[i]进行从大到小排序
     75 map<int, int>::iterator it;
     76 
     77 void init()
     78 {
     79     cnt = cur = 1;
     80     time = -1;
     81     memset(head, 0, sizeof(head));
     82     memset(f, 0, sizeof(f));
     83     memset(d, 0, sizeof(d));
     84     memset(color, 0, sizeof(color));
     85     memset(belong, 0, sizeof(belong));
     86     mp.clear();
     87 }
     88 
     89 int main()
     90 {
     91     int n, m, u, v, i;
     92     while (~scanf("%d%d", &n, &m))
     93     {
     94         init();
     95         for (i = 0; i < m; i++)
     96         {
     97             scanf("%d%d", &u, &v);
     98              addedge(u, v);
     99         } 
    100         for (i = 1; i <= n; i++)//得到f
    101             if (!color[i])
    102                 dfs_visit(i);
    103         //sort(f, f + n, cmp);
    104         for (i = 1; i <=n; i++)//对f排序
    105             mp[f[i]] = i;    
    106         memset(color, 0, sizeof(color));
    107         for (it = mp.begin(); it != mp.end(); ++it)//对反图进行dfs
    108         {
    109             if (!color[it->second])
    110             {
    111                 dfs_visit_t(it->second);
    112                 cur++;
    113             }        
    114         }    
    115         for (i = 1; i <=n; i++)
    116             printf("%d ", belong[i]);
    117     }
    118     return 0;
    119 }

    Tarjan算法只需一次dfs,而且不用求反图,dfs找最早祖先点(最先被发现)也就是寻找B边。

    使用LOW函数测试此条件
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <algorithm>
     4 #include <iomanip>
     5 #include <set>
     6 #include <map>
     7 #include <vector>
     8 #include <queue>
     9 #include <stack>
    10 #define INF 0x7fffffff
    11 using namespace std;
    12 #define N 1000
    13 
    14 stack<int> s;
    15 int head[N], cnt;
    16 struct node 
    17 {
    18     int next, to;
    19 }edge[N * 2];
    20 
    21 void addedge(int from, int to)
    22 {
    23     cnt++;
    24     edge[cnt].next = head[from];
    25     edge[cnt].to = to;
    26     head[from] = cnt;
    27 }
    28 //int f[N];//finishtime
    29 int pre[N];//discovertime 
    30 //int color[N];//init 0 denote white; 1 denote gray discover; 2 denote black finish 
    31 int time; 
    32 int id[N];//which scc
    33 int low[N];//
    34 int cur;//current scc
    35 void dfs_visit(int x)
    36 {
    37     low[x] = pre[x] = ++time;
    38     s.push(x);
    39     int i, j;
    40     for (i = head[x]; i; i = edge[i].next)
    41     {
    42         j = edge[i].to;
    43         if (!pre[j])
    44         {
    45             dfs_visit(j);
    46         }
    47         if (low[j] < low[x])//找最小的low[x],即是否存在后向边(B边)
    48             low[x] = low[j];
    49     }
    50     if (low[x] == pre[x])//找到了一个scc
    51     {
    52         do
    53         {
    54             i = s.top();
    55             s.pop();
    56             low[i] = INF;
    57             id[i] = cur;
    58         }while (i != x);
    59         cur++;
    60     }
    61 }
    62 
    63 void init()
    64 {
    65     cnt = cur = 1;
    66     time = 0;
    67     memset(head, 0, sizeof(head));
    68     memset(pre, 0, sizeof(pre));
    69     memset(low, 0, sizeof(low));
    70     memset(id, 0, sizeof(id));
    71     while (!s.empty())
    72         s.pop();
    73 }
    74 
    75 int main()
    76 {
    77     int n, m, u, v, i;
    78     while (~scanf("%d%d", &n, &m))
    79     {
    80         init();
    81         for (i = 0; i < m; i++)
    82         {
    83             scanf("%d%d", &u, &v);
    84              addedge(u, v);
    85         }     
    86         for (i = 1; i <= n; i++)
    87             if (!pre[i])
    88                 dfs_visit(i);
    89         for (i = 1; i <=n; i++)
    90             printf("%d ", id[i]);
    91     }
    92     return 0;
    93 }

    Gabow算法:思路与tarjan思路一样,但是用一个stack替代了low数组,使得交换次数减小

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <algorithm>
     4 #include <iomanip>
     5 #include <set>
     6 #include <map>
     7 #include <vector>
     8 #include <queue>
     9 #include <stack>
    10 #define INF 0x7fffffff
    11 using namespace std;
    12 #define N 1000
    13 
    14 stack<int> s;
    15 stack<int> p;
    16 int head[N], cnt;
    17 struct node 
    18 {
    19     int next, to;
    20 }edge[N * 2];
    21 
    22 void addedge(int from, int to)
    23 {
    24     cnt++;
    25     edge[cnt].next = head[from];
    26     edge[cnt].to = to;
    27     head[from] = cnt;
    28 }
    29 //int f[N];//finishtime
    30 int pre[N];//discovertime 
    31 //int color[N];//init 0 denote white; 1 denote gray discover; 2 denote black finish 
    32 int time; 
    33 int id[N];//which scc
    34 int low[N];//
    35 int cur;//current scc
    36 void dfs_visit(int x)
    37 {
    38     low[x] = pre[x] = ++time;
    39     s.push(x);
    40     p.push(x);
    41     int i, j;
    42     for (i = head[x]; i; i = edge[i].next)
    43     {
    44         j = edge[i].to;
    45         if (!pre[j])
    46             dfs_visit(j);
    47         if (!id[j])//该点未在已求的scc中
    48             while (pre[j] < pre[p.top()])存在后向边,出栈
    49                 p.pop();    
    50     }
    51     if (p.top() == x)//找到一个scc
    52     {
    53         p.pop();
    54         do
    55         {
    56             i = s.top();
    57             id[i] = cur;
    58             s.pop();
    59         }while (i != x);
    60         cur++;
    61     }
    62 }
    63 
    64 void init()
    65 {
    66     cnt = cur = 1;
    67     time = 0;
    68     memset(head, 0, sizeof(head));
    69     memset(pre, 0, sizeof(pre));
    70     memset(low, 0, sizeof(low));
    71     memset(id, 0, sizeof(id));
    72     while (!s.empty())
    73         s.pop();
    74     while (!p.empty())
    75         p.pop();
    76 }
    77 
    78 int main()
    79 {
    80     int n, m, u, v, i;
    81     while (~scanf("%d%d", &n, &m))
    82     {
    83         init();
    84         for (i = 0; i < m; i++)
    85         {
    86             scanf("%d%d", &u, &v);
    87              addedge(u, v);
    88         }     
    89         for (i = 1; i <= n; i++)
    90             if (!pre[i])
    91                 dfs_visit(i);
    92         for (i = 1; i <=n; i++)
    93             printf("%d ", id[i]);
    94     }
    95     return 0;
    96 }
  • 相关阅读:
    (拿来主义) SpringCloud | 第四篇: 断路器(Hystrix)
    (拿来主义) SpringCloud | 第三篇: 服务消费者(Feign)
    (拿来主义) SpringCloud | 第二篇: 服务消费者(rest+ribbon)
    (拿来主义) SpringCloud | 第一篇: 服务的注册与发现(Eureka)
    (拿来主义-10) Spring Boot中使用Swagger2构建强大的RESTful API文档(五)
    (拿来主义-9) Spring Boot构建RESTful API与单元测试(四)
    (拿来主义-8) Spring Boot属性配置文件详解(三)
    (拿来主义-7) Spring Boot工程结构推荐(二)
    springMVC配置文件路径问题
    实现可用的插件系统
  • 原文地址:https://www.cnblogs.com/jecyhw/p/3456759.html
Copyright © 2020-2023  润新知