图的连通性Tarjan(有向图)

图的连通性Tarjan(有向图)


前置知识

  • 强联通图:强连通图(Strongly Connected Graph)是指在有向图G中,如果对于任意两点u, v,从u到v和从v到u都有路径,则称G是强连通图
  • 极大强连通子图:一个有向图中无法再加一个点的强连通子图
  • 强连通分量(scc):一个有向图的极大强连通子图
  • 领接表存图
  • dfs

 

解决问题


例题:

1.[HAOI2006]受欢迎的牛

 1 //题意为求一个图中唯一的出度为0的强联通 
 2 
 3 #include <bits/stdc++.h>
 4 using namespace std;
 5 const int MAXN = 100001;
 6 const int MAXM = 50001;
 7 int n, m;
 8 
 9 int head[MAXN], cnt, nxt[MAXM], v[MAXM];
10 void add(int x, int y) {
11     nxt[++cnt] = head[x];
12     head[x] = cnt;
13     v[cnt] = y;
14 }
15 
16 int dfn[MAXN], low[MAXN], ind;//dfn[u] : dfs图过程中搜到u的顺序 ,low[u] : u和u可到的子树中dfn的最小值 
17 int s[MAXN], stp;//
18 int scccnt, sccnum[MAXN], sccsize[MAXN];
19 
20 int out[MAXN];//每个强联通的出度 
21 int ans = 0;
22 
23 void tarjan(int now) {
24     dfn[now] = low[now] = ++ind;
25     s[stp++] = now;//stp存的是栈顶的上一个位置 
26     
27     for (int i = head[now]; i ; i = nxt[i]) {
28         
29         if(!dfn[v[i]]) {
30             tarjan(v[i]);
31             low[now] = min(low[v[i]], low[now]);//树枝边 
32         }
33         else if(!sccnum[v[i]]) {
34             low[now] = min(dfn[v[i]], low[now]);//前后向边 
35         }
36         
37     } 
38     
39     
40     if(dfn[now] == low[now]) { // 分割点 
41         scccnt++;
42         while(s[stp] != now) {
43             sccnum[s[--stp]] = scccnt;
44             sccsize[scccnt]++; 
45         } 
46     }
47     
48     return;
49 }
50 
51 int main() {
52     
53     scanf("%d%d", &n, &m);
54     for (int i = 1; i <= m; i++) {
55         int x, y;
56         scanf("%d%d", &x, &y);
57         add(x, y);
58     }
59     
60     for (int i = 1; i <= n; i++) {
61         if(!dfn[i]) tarjan(i);
62     }
63     //for (int i = 1; i <= n; i++) printf("dfn[%d] = %d, low[%d] = %d, sccnum[%d] = %d\n", i, dfn[i], i, low[i], i, sccnum[i]);
64     
65     //求唯一的出度为0的强联通 
66     for (int i = 1; i <= n; i++) {
67         for (int j = head[i]; j ; j = nxt[j]) {
68             if(sccnum[i] != sccnum[v[j]])
69                 out[sccnum[i]]++;
70         }
71     }
72     bool flag = 0;
73     for (int i = 1; i <= scccnt; i++) {
74         if(flag == 1 && out[i] == 0) {
75             printf("0");
76             return 0;
77         }
78         else if(out[i] == 0) {
79             ans = sccsize[i];
80             flag = 1;
81         }
82     }
83     
84     
85     printf("%d", ans);
86     
87     
88     return 0;
89 }

猜你喜欢

转载自www.cnblogs.com/hangzz/p/11917884.html