1. 程式人生 > >割點【模板】 Luogu P3388 【模板】割點(割頂)

割點【模板】 Luogu P3388 【模板】割點(割頂)

題目描述:戳這裡
題解:
邊雙的模板題啦。
我們可以考慮tarjan刷有向圖的環的方法,只要稍稍修改,就能AC了。
我們需要注意一下兩點:
1.對於每一個點,只要它的任意下一層的子樹中有一個點的low[x]>dfn[]這個點就可以是割點了
2.對於一個根節點,如果它的子樹個數>=2,那麼它就一定是割點。

其它和tarjan就比較像了。

程式碼如下:

#include<cstdio>
#include<string>
#include<algorithm>
using namespace
std; const int maxn=100005; int n,m,n1,tot,lnk[maxn],son[2*maxn],nxt[2*maxn],dfn[maxn],low[maxn],ans[maxn]; void add(int x,int y) {son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;} void dfs(int x,int fa){ dfn[x]=low[x]=++tot; int ch=0; for (int j=lnk[x];j;j=nxt[j]){ if (!dfn[son[j]]) { dfs(son[j],fa); low[x]=min(low[x],low[son[j]]); if
(low[son[j]]>=dfn[x]&&x!=fa) ans[x]=1; if (x==fa) ch++; } low[x]=min(low[x],dfn[son[j]]); } if (ch>=2&&x==fa) ans[x]=1; } int main(){ scanf("%d %d",&n,&m); for (int i=1;i<=m;i++) { int x,y; scanf("%d %d",&x,&y); add(x,y); add(y,x); } tot=0
; for (int i=1;i<=n;i++) if (!dfn[i]) dfs(i,i); for (int i=1;i<=n;i++) if (ans[i]) n1++; printf("%d\n",n1); for (int i=1;i<=n;i++) if (ans[i]) printf("%d ",i); printf("\n"); return 0; }