#include<bis/stdc++.h>
using namespace std;
const int maxn=10000+10;
typedef pair<int,int> Edge;
int index=0,rootson=0;
vector<bool> vis(maxn);
vector<int> dfn(maxn),low(maxn),cutvex;
vector<vector<int> > G(maxn);
vector<Edge> bridge;
void Tarjan(int u,int father){
dfn[u]=low[u]=++index;
vis[u]=true;
bool isCut=false;
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));
if(dfn[u]<=low[v]) isCut=true;
}
else if(father!=v) //只能由非父子边更新
low[u]=min(low[u],dfn[v]);
}
if(father==1&&rootson!=-1) rootson++;
if(rootson>1) cutvex.push_back(1),rootson=-1;
if(u!=1&&isCut) cutvex.push_back(u);
}
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); //联通的
sort(cutvex.begin(),cutvex.end());
sort(bridge.begin(),bridge.end());
for(int i=0;i<cutvex.size();i++)
cout<<cutvex[i]<<endl;
for(int i=0;i<bridge.size();i++)
cout<<bridge[i].first<<','<<bridge[i].second<<endl;
return 0;
}
桥和割点
定义:
割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。
桥:无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。
题意:
给你一些点,某些点之间有边。求有多少个点是割点
变量:
low[u]定义为u或者u的子树中能够通过非父子边追溯到的最早的节点的DFS开始时间
dfn[u]表示dfs下u的开始时间
判断割点方法:
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得dfn(u)<=low(v)。也就是u的子树中的v点无法到达u之前的点,所以u点去掉就是两个连通分支,所以u为割点