图的割点
传送门:https://www.luogu.org/problem/P3388
还有两点要注意的
1.割点可能有很多个
2.无向图和有向图都有割点
然后我们来看一看如何实现割点
方案一:枚举去掉每个点的情况,DFS判断时间复杂度O(n^2)
方案二:Tarjan实现
同样是用dfn表示搜索次序,但是low表示可以最早回溯到的祖先的dfn值
之后就和tarjan没有太多不同了
#include<bits/stdc++.h> using namespace std; int n,m; struct edge{ int next,to; }e[200009];int tot; int first[100009]; int dfn[100009]; int low[100009]; int js; int ans; bool book[100009]; inline void add_edge(int a,int b) { e[++tot].to=b; e[tot].next=first[a]; first[a]=tot; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } void tarjan(int now,int fa)//now是我在那里,fa是我的爸爸是谁 { js++; dfn[now]=js,low[now]=js; int child=0;//记录有几个子树 for(int i=first[now];i;i=e[i].next) { if(dfn[e[i].to]==0) { tarjan(e[i].to,now); if(low[now]>low[e[i].to])low[now]=low[e[i].to]; if(now==fa)child++;//如果是根结点就+1 if(now!=fa&&low[e[i].to]>=dfn[now])book[now]=true;//如果不是根结点并且它的子节点不通过它就无法回到之前的节点,那么说明它就是割点 } else if(e[i].to!=fa&&dfn[e[i].to]<=low[now]) { low[now]=dfn[e[i].to]; } } if(now==fa&&child>=2)book[now]=true;//如果是根结点,并且儿子数量有两个以上那么明显就是割点 return; } int main() { n=read(),m=read(); for(register int i=1;i<=m;i++) { int a=read(),b=read(); add_edge(a,b); add_edge(b,a); } for(int i=1;i<=n;i++) { if(dfn[i]==0) { tarjan(i,i);//因为割点有多个,并且图可能本身不连通,所以多次枚举 } } for(int i=1;i<=n;i++) { if(book[i]==true)ans++; } cout<<ans<<endl; for(int i=1;i<=n;i++) { if(book[i]==true) { cout<<i<<" "; } } return 0; }