边双连通分支:不包含桥的极大连通子图
算法思路:
只需在求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个
边双连通分支。桥不属于任何一个边双连通分支,其余的边和每个顶点都属于且只属于
一个边双连通分支。
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10000+10;
typedef pair<int,int> Edge;
int index=0;
vector<bool> vis(maxn);
vector<int> dfn(maxn),low(maxn);
vector<vector<int> > G(maxn);
vector<Edge> bridge;
void Tarjan(int u,int father)
{dfn[u]=low[u]=++index;vis[u]=true;for(int i=0;i<G[u].size();i++){int v=G[u][i];if(!vis[v]){Tarjan(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<low[v]) bridge.push_back(Edge(u,v));}else if(father!=v) //只能由非父子边更新 low[u]=min(low[u],dfn[v]);}
}
int main()
{int n,m;cin>>n>>m;while(m--){int u,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}Tarjan(1,0); //联通的for(int i=0;i<bridge.size();i++){ //删去桥 int u=bridge[i].first,v=bridge[i].second;for(int j=0;j<G[u].size();j++){if(G[u][j]==v) G[u].erase(G[u].begin()+j);}for(int j=0;j<G[v].size();j++){if(G[v][j]==u) G[v].erase(G[v].begin()+j);}}return 0;
}