【洛谷P3388】【模板】割點
阿新 • • 發佈:2018-12-30
都快忘了割點怎麼搞了
對所有點分兩類
1.根節點 2.非根節點
顯然根節點是很好做的 只需要數一下有沒有兩個子樹以上
對於非根節點 利用tarjan演算法
回憶到dfn的定義:時間戳,即在dfs中第幾個被訪問到 low:經過最多一條後向邊/棧中橫叉邊能到達的最小的節點時間戳
對於當前節點now來說,把整個圖分成了兩個子樹。假如low[vis]>=dfn[now],(注意不要把時間戳和編號序搞混) 也就是說vis節點最多隻能追溯到now這棵子樹以內,而不能回到另一顆子樹去。就因為這個特殊的vis,now就成了割點。
然後注意細節吧 比如輸出 以及統計答案要單獨掃一遍 因為會有重複的
#include<bits/stdc++.h> #define N 20005 #define M 100005 using namespace std; template<class T> inline void read(T &x) { x=0; static char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); } struct Edge { int to,next,val; }edge[2*M]; int n,m,tot,first[N]; inline void addedge(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot; } int dfn[N],low[N],sign,cnt; bool cut[N]; inline void dfs(int now,int fa) { int child=0; dfn[now]=low[now]=++sign; for(int u=first[now];u;u=edge[u].next) { int vis=edge[u].to; if(vis==fa) continue; if(!dfn[vis]) { ++child; dfs(vis,now); low[now]=min(low[vis],low[now]); if(low[vis]>=dfn[now]&&fa!=0) cut[now]=true; //非根節點 } else low[now]=min(low[now],dfn[vis]); } if(fa==0&&child>=2) cut[now]=true; //根節點 } int main() { read(n); read(m); for(int i=1,u,v;i<=m;i++) read(u),read(v),addedge(u,v),addedge(v,u); for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i,0); for(int i=1;i<=n;i++) if(cut[i]) ++cnt; //注意要在這裡掃一遍 而不是在dfs裡記錄 因為會重複 cout<<cnt<<endl; for(int i=1;i<=n;i++) if(cut[i]) cout<<i<<" "; return 0; }