无向图的割点
割点:如果删去一个点以及相关的边,图变为不连通,则称这个点为割点
割点条件 1 or 2
1.(树)根结点u,有两个或者多个子结点(子树)
2.非(树)根结点u,存在边(u,v),使得v和所有后代都没有反向边可以连回 u 的祖先,即low[v]>=dfn[u]
以下割点代码
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> #include <cstring> #include <set> using namespace std; const int MAXN=100010; int n,m,nume,depth,ans; int head[MAXN],low[MAXN],dfn[MAXN],fa[MAXN]; bool iscut[MAXN]; struct Edge { int nex,to; }e[MAXN*2]; int in() { int x=0,flag=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') flag=-1;ch=getchar();} while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*flag; } void addedge(int from,int to) { e[++nume]=(Edge){head[from],to}; head[from]=nume; } void tarjan(int u) { int child=0; low[u]=dfn[u]=++depth; for (int i=head[u];i;i=e[i].nex) { int v=e[i].to; if (!dfn[v]) { child++; fa[v]=u; tarjan(v); low[u]=min(low[u],low[v]); if ((low[v]>=dfn[u]&&fa[u]!=u)||(child>1&&fa[u]==u)) { if (!iscut[u]) ans++; iscut[u]=true; } //if (low[v]>dfn[u]) 桥 } else { if (u!=fa[v]) low[u]=min(low[u],dfn[v]); } } } int main() { n=in(),m=in(); for (int i=1;i<=m;i++) { int u=in(),v=in(); addedge(u,v); addedge(v,u); } for (int i=1;i<=n;i++) fa[i]=i; for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); printf("%d\n",ans); for (int i=1;i<=n;i++) if (iscut[i]) printf("%d ",i); return 0; }