tarjan[强连通分量][求割边割点][缩点]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tarjan[强连通分量][求割边割点][缩点]相关的知识,希望对你有一定的参考价值。

强连通分量:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=100000+15;
 5 struct Edge {
 6     int x,y,next;
 7     Edge(int x=0,int y=0,int next=0):
 8         x(x),y(y),next(next) {}
 9 } edge[maxn];
10 int sumedge,head[maxn];
11 int n,m;
12 int ins(int x,int y) {
13     edge[++sumedge]=Edge(x,y,head[x]);
14     return head[x]=sumedge;
15 }
16 bool instack[maxn];
17 int top,Stack[maxn];
18 int dfn[maxn],low[maxn],tim;
19 bool vis[maxn];
20 int col[maxn],sumcol;
21 int dfs(int now) {
22     dfn[now]=low[now]=++tim;
23     Stack[++top]=now;
24     vis[now]=true;
25     instack[now]=true;
26     for (int u=head[now]; u; u=edge[u].next)
27         if (instack[edge[u].y])
28             low[now]=min(low[now],dfn[edge[u].y]);
29         else if (!vis[edge[u].y]) {
30             dfs(edge[u].y);
31             low[now]=min(low[now],low[edge[u].y]);
32         }
33     if (low[now]==dfn[now]) {
34         sumcol++;
35         col[now]=sumcol;
36         while (Stack[top]!=now) {
37             col[Stack[top]]=sumcol;
38             instack[Stack[top]]=false;
39             top--;
40         }
41         instack[now]=false;
42         top--;
43     }
44     return 0;
45 }
46 int main() {
47     scanf("%d%d",&n,&m);
48     for (int i=1; i<=m; i++) {
49         int x,y;
50         scanf("%d%d",&x,&y);
51         ins(x,y);
52     }
53     for (int i=1; i<=n; i++)
54         if (!vis[i]) dfs(i);
55     return 0;
56 }

缩点:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=100000+15;
 5 struct Edge {
 6     int x,y,next;
 7     Edge(int x=0,int y=0,int next=0):
 8         x(x),y(y),next(next) {}
 9 } edge[maxn],edge2[maxn];
10 map <int, bool > Map[maxn];
11 int sumedge,head[maxn];
12 int n,m;
13 int sumedge2,head2[maxn];
14 int ins2(int x,int y) {
15     edge2[++sumedge2]=Edge(x,y,head2[x]);
16     return head2[x]=sumedge;
17 }
18 int ins(int x,int y) {
19     edge[++sumedge]=Edge(x,y,head[x]);
20     return head[x]=sumedge;
21 }
22 bool instack[maxn];
23 int top,Stack[maxn];
24 int dfn[maxn],low[maxn],tim;
25 bool vis[maxn];
26 int col[maxn],sumcol;
27 int dfs(int now) {
28     dfn[now]=low[now]=++tim;
29     Stack[++top]=now;
30     vis[now]=true;
31     instack[now]=true;
32     for (int u=head[now]; u; u=edge[u].next)
33         if (instack[edge[u].y])
34             low[now]=min(low[now],dfn[edge[u].y]);
35         else if (!vis[edge[u].y]) {
36             dfs(edge[u].y);
37             low[now]=min(low[now],low[edge[u].y]);
38         } else {
39         }
40     if (low[now]==dfn[now]) {
41         sumcol++;
42         col[now]=sumcol;
43         while (Stack[top]!=now) {
44             col[Stack[top]]=sumcol;
45             instack[Stack[top]]=false;
46             top--;
47         }
48         instack[now]=false;
49         top--;
50     }
51     return 0;
52 }
53 int main() {
54     scanf("%d%d",&n,&m);
55     for (int i=1; i<=m; i++) {
56         int x,y;
57         scanf("%d%d",&x,&y);
58         ins(x,y);
59     }
60     for (int i=1; i<=n; i++)
61         if (!vis[i]) dfs(i);
62     for (int i=1; i<=n; i++)
63         for (int u=head[i]; u; u=edge[u].next)
64             if (col[i]!=col[edge[u].y])
65                 if (Map[col[i]].find(col[edge[u].y])==Map[col[i]].end()) {
66                     Map[col[i]][col[edge[u].y]]=true;
67                     ins2(col[i],col[edge[u].y]);
68                 }
69     return 0;
70 }

 求割边割点:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=100000+15;
 5 struct Edge {
 6     int x,y,next;
 7     Edge(int x=0,int y=0,int next=0):
 8         x(x),y(y),next(next) {}
 9 } edge[maxn*2];
10 int sumedge,head[maxn],n,m;
11 int ins(int x,int y) {
12     edge[++sumedge]=Edge(x,y,head[x]);
13     return head[x]=sumedge;
14 }
15 int low[maxn],dfn[maxn],tim;
16 bool vis[maxn];
17 bool cutedge[maxn],cutpoint[maxn];
18 int dfs(int now,int pre) { //需要多记录父边的编号
19     dfn[now]=low[now]=++tim;
20     vis[now]=true;
21     int sum=0; //树边数目
22     bool boo=false;
23     for (int u=head[now]; u!=-1; u=edge[u].next)
24         if ((u^1)!=pre)  //确定不是父边
25             if (!vis[edge[u].y]) {
26                 sum++;
27                 dfs(edge[u].y,u);
28                 if (low[edge[u].y]>dfn[now]) { //判断割边
29                     cutedge[u/2]=true;  //u/2为边的实际编号
30                 }
31                 if (low[edge[u].y]>=dfn[now])  //判断割点
32                     boo=true;
33                 low[now]=min(low[now],low[edge[u].y]);
34             } else {
35                 low[now]=min(low[now],dfn[edge[u].y]);
36             }
37     if (pre==-1) { //分情况判断割点
38         if (sum>1) cutpoint[now]=true;
39     } else {
40         if (boo) cutpoint[now]=true;
41     }
42     return 0;
43 }
44 int main() {
45     scanf("%d%d",&n,&m);
46     sumedge=-1;  //使得代表同一条边的两边编号更有关系
47     memset(head,-1,sizeof(head));
48     for (int i=1; i<=m; i++) {
49         int x,y;
50         scanf("%d%d",&x,&y);
51         ins(x,y);
52         ins(y,x);
53     }
54     for (int i=1; i<=n; i++)
55         if (!vis[i]) dfs(i,-1);
56     for (int i=1; i<=n; i++)
57         if (cutpoint[i]) printf("%d\n",i) ;
58     return 0;
59 }

 

以上是关于tarjan[强连通分量][求割边割点][缩点]的主要内容,如果未能解决你的问题,请参考以下文章

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

(转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

8/15 缩点+割点(割顶)+桥(割边)+字符串哈希

学习整理Tarjan:强连通分量+割点+割边

tarjan算法(强连通分量 + 强连通分量缩点 + 桥 + 割点 + LCA)