概念:
边双连通分量:不存在桥的无向图为边双连通图, 极大边双连通图为边双连通分量(以点存)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define N 100010 using namespace std; struct node{ int v,nextt; }e[N<<1]; //c[x]储存x所在的e-DCC的编号,dcc存e-DCC的数量 int head[N],tot=1,n,m,cnt,dfn[N],low[N],c[N],bridge[N],dcc; void addedge(int u,int v){ e[tot].v=v; e[tot].nextt=head[u]; head[u]=tot++; } void tarjan(int u,int in_edge){//in_edge表示递归进入每个节点的边的编号 dfn[u]=low[u]=++cnt; for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(!dfn[v]){ tarjan(v,i); low[u]=min(low[u],low[v]);//在搜索树上的边 if(low[v]>dfn[u])//桥判定法则 bridge[i]=bridge[i^1]=1;//这条边和它的反向边都是桥 } else if(i!=(in_edge^1)) low[u]=min(low[u],dfn[v]);//不在搜索树上的边 } }//Tarjan标记桥 void dfs(int x){ c[x]=dcc;//标号 for(int i=head[x];~i;i=e[i].nextt){ int v=e[i].v; if(c[v]||bridge[i])continue;//如果已经有标号了或者这条边是桥就不访问 dfs(v); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); addedge(x,y);addedge(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);//每个联通块都进去标号 } } for(int i=1;i<=n;i++) printf("%d %d ",i,c[i]); return 0; }
点双连通分量:不存在割点的无向图为点双连通图, 极大点双连通图为点双连通分量(以边存)
模板:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void tarjan(int x){ dfn[x]=low[x]=++cnt; stk[++top]=x;//第一次访问该节点,入栈 if(x==rt && head[x]==-1){//判断孤立点,直接插入vector dcc[++num].push_back(x); return; } int flag=0; for(int i=head[x];i;i=nxt(i)){ int y=to(i); if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(low[y]>=dfn[x]){//割点判定法则 flag++; if(x!=rt||flag>1)cut[x]=1; num++;int z;//根据上面描述的做法,把所有栈中的节点插入vector do{ z=stk[top--]; dcc[num].push_back(z);//全部插入 }while(z!=y); dcc[num].push_back(x);//包括x自己 } }else low[x]=min(low[x],dfn[y]);//不在搜索树上,继续更新low } } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); addedge(x,y);addedge(y,x); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int i=1;i<=num;i++){ printf("%d:",i);//第i个v-DCC for(int j=0;j<dcc[i].size();j++) printf(" %d",dcc[i][j]);//第i个v-DCC中所有的点 putchar(' '); } return 0; }