tarjan求强连通分量 + 缩点 + 求割点割边
强连通分量:
引用度娘:“有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。”
就是在一幅图里,任意两点可以相互到达,这一幅图就是一个强连通分量。
这幅图中强连通分量有三个,为:1-2-3、4、5 。
强连通分量的应用:
1、缩点。
2、求割点和割边的数量。
代码:
tarjan 模版 + 缩点
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define MOD 998244353 4 #define INF 0x3f3f3f3f 5 #define mem(a,x) memset(a,x,sizeof(a)) 6 using namespace std; 7 int dfn[50005]; 8 int low[50005]; 9 int vis[50005]; 10 int stacks[50005]; 11 int color[50005]; 12 int cnt[50005]; 13 int deep,sum,top; 14 int n,m; 15 vector<int>g[50005]; 16 void tarjan(int u) 17 { 18 dfn[u]=++deep; 19 low[u]=deep; 20 vis[u]=1; 21 stacks[++top]=u; 22 for(int i=0;i<g[u].size();i++){ 23 int v=g[u][i]; 24 if(!dfn[v]) 25 { 26 tarjan(v); 27 low[u]=min(low[u],low[v]); 28 }else{ 29 if(vis[v]){ 30 low[u]=min(low[v],low[u]); 31 } 32 } 33 } 34 if(dfn[u]==low[u]) 35 { 36 color[u]=++sum; 37 vis[u]=0; 38 while(stacks[top]!=u) 39 { 40 color[stacks[top]]=sum; 41 vis[stacks[top--]]=0; 42 } 43 top--; 44 } 45 } 46 int main() 47 { 48 deep=0; 49 top=0; 50 sum=0; 51 mem(dfn,0); 52 mem(vis,0); 53 mem(cnt,0); 54 scanf("%d %d",&n,&m); 55 while(m--){ 56 int from,to; 57 scanf("%d %d",&from,&to); 58 g[from].push_back(to); 59 } 60 for(int i=1;i<=n;i++){ 61 if(!dfn[i]){ 62 tarjan(i); 63 } 64 } 65 int num=0; 66 for(int i=1;i<=n;i++){ 67 cnt[color[i]]++; 68 } 69 for(int i=1;i<=sum;i++){ 70 if(cnt[i]>1)num++; 71 } 72 cout<<num; 73 return 0; 74 }
tarjan 求割点
在原来的tarjan 基础上 加一个特判:如果一个点的为根节点且这个点有两个及以上的儿子,这个点就是割点。
代码:
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define MOD 998244353 4 #define INF 0x3f3f3f3f 5 #define mem(a,x) memset(a,x,sizeof(a)) 6 using namespace std; 7 int n,m; 8 int deep=0,root; 9 vector<int>g[200015]; 10 int dfn[100015]; 11 int low[100015]; 12 int stack[100015]; 13 int vis[100015]; 14 int iscut[100015]; 15 int tarjan(int u,int fa) 16 { 17 int child=0,lowu; 18 lowu=dfn[u]=++deep; 19 int sz=g[u].size(); 20 for(int i=0;i<sz;i++) 21 { 22 int v=g[u][i]; 23 if(!dfn[v]) 24 { 25 int v=g[u][i]; 26 int lowv=tarjan(v,u); 27 lowu=min(lowu,lowv); 28 if(lowv>dfn[u]) 29 { 30 iscut[u]=1; 31 } 32 }else{ 33 if(v!=fa&&dfn[v]<dfn[u]) 34 { 35 lowu=min(lowu,dfn[v]); 36 } 37 } 38 } 39 if(fa<0&&child==1) 40 { 41 iscut[u]=0; 42 } 43 low[u]=lowu; 44 return lowu; 45 } 46 int main() 47 { 48 scanf("%d %d",&n,&m); 49 for(int i=1;i<=m;i++){ 50 int from,to; 51 scanf("%d %d",&from,&to); 52 g[from].push_back(to); 53 g[to].push_back(from); 54 } 55 for(int i=1;i<=n;i++){ 56 if(!vis[i]){ 57 root=i; 58 tarjan(i,-1); 59 } 60 } 61 int ans=0; 62 for(int i=1;i<=n;i++){ 63 if(iscut[i]){ 64 ans++; 65 } 66 } 67 printf("%d\n",ans); 68 for(int i=1;i<=n;i++){ 69 if(iscut[i]){ 70 printf("%d ",i); 71 } 72 } 73 return 0; 74 }
求割边
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #define hi printf("hi!"); 7 using namespace std; 8 9 vector<pair<int,int> >bridge; 10 vector<int> g[10010]; 11 int dfn[10010],low[10010]; 12 int deep,root,n,m,ans; 13 14 int tarjan(int u,int fa) 15 { 16 int lowu; 17 lowu=dfn[u]=++deep; 18 int sz=g[u].size(); 19 for(int i=0;i<sz;i++) 20 { 21 int v=g[u][i]; 22 if(!dfn[v]) 23 { 24 int lowv=tarjan(v,u); 25 lowu=min(lowu,lowv); 26 if(lowv>dfn[u]) 27 { 28 int from,to; 29 from=u; 30 to=v; 31 if(from>to) 32 { 33 swap(from,to); 34 } 35 bridge.push_back(make_pair(from,to)); 36 } 37 } 38 else 39 { 40 if(v!=fa&&dfn[v]<dfn[u]) 41 { 42 lowu=min(lowu,dfn[v]); 43 } 44 } 45 } 46 low[u]=lowu; 47 return lowu; 48 } 49 50 int main() 51 { 52 scanf("%d%d",&n,&m); 53 for(int i=1;i<=m;i++) 54 { 55 int from,to; 56 scanf("%d%d",&from,&to); 57 g[from].push_back(to); 58 g[to].push_back(from); 59 } 60 for(int i=1;i<=n;i++) 61 { 62 if(!dfn[i]) 63 { 64 root=i; 65 tarjan(i,-1); 66 } 67 } 68 for(int i=0;i<bridge.size();i++) 69 { 70 printf("%d %d\n",bridge[i].first,bridge[i].second); 71 } 72 }
越自律,越自由