书P401
需要具备的知识:
①:tarjan求割点与割边:https://blog.nowcoder.net/n/dc5fbd4588164fb4b37847a11ea7f499
若一张无向图不存在割点,则为点双连通图。
若一张无向图不存在割边(桥),则为边双连通图。
无向图的极大点双连通子图为点双连通分量,简称“v-DCC”。
无向图的极大边双连通子图为边双连通分量,简称“e-DCC”。
二者统称为双连通分量,简称“DCC”。
1、边双连通分量
模版:https://www.luogu.com.cn/problem/T103489
#include <bits/stdc++.h> using namespace std; const int SIZE=3e5+1; int head[SIZE],ver[SIZE*2],Next[SIZE*2]; int dfn[SIZE],low[SIZE]; bool bridge[SIZE*2]; int n,m,tot,num; int c[SIZE],dcc; void dfs(int x) { c[x]=dcc; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(c[y]||bridge[i]) continue; dfs(y); } } void add(int x,int y) { ver[++tot]=y,Next[tot]=head[x],head[x]=tot; } void tarjan(int x,int in_edge) { dfn[x]=low[x]=++num; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(!dfn[y]) { tarjan(y,i); low[x]=min(low[x],low[y]); if(low[y]>dfn[x]) { bridge[i]=bridge[i^1]=true; } } else if(i!=(in_edge^1)) low[x]=min(low[x],low[y]); } } int main() { cin>>n>>m; tot=1; for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; add(x,y); add(y,x); } for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i,0); } for(int i=1;i<=n;i++) { if(!c[i]) { ++dcc; dfs(i); } } cout<<dcc<<endl; //cout<<"There are "<<dcc<<" e-DCCs."<<endl; /*for(int i=1;i<=n;i++) { cout<<i<<" belongs to DCC "<<c[i]<<"."<<endl; }*/ return 0; }
2、
3、点双连通分量
模版题:https://www.luogu.com.cn/problem/P3225
#include <bits/stdc++.h> using namespace std; const int SIZE=100010; int head[SIZE],ver[SIZE*2],Next[SIZE*2]; int dfn[SIZE],low[SIZE],Stack[SIZE]; bool cut[SIZE*2]; vector<vector<int> > dcc; int n,m,tot,num,root,top,cnt; void add(int x,int y) { ver[++tot]=y,Next[tot]=head[x],head[x]=tot; } void tarjan(int x) { dfn[x]=low[x]=++num; Stack[++top]=x; if(x==root&&head[x]==0) { dcc[++cnt].push_back(x); return; } int flag=0; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]) { flag++; if(x!=root||flag>1) cut[x]=true; cnt++; int z; while(z!=y) { z=Stack[top--]; dcc[cnt].push_back(z); } dcc[cnt].push_back(x); } } else low[x]=min(low[x],dfn[y]); } } int main() { cin>>n>>m; tot=1; for(int i=0;i<=n;i++) { dcc.push_back({}); } for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; if(x==y) continue; add(x,y); add(y,x); } for(int i=1;i<=n;i++) { if(!dfn[i]) { root=i; tarjan(i); } } for(int i=1;i<=cnt;i++) { cout<<"v-DCC "<<i<<":"; for(int j=0;j<dcc[i].size();j++) { cout<<" "<<dcc[i][j]; } cout<<endl; } return 0; }