1. 程式人生 > >【洛谷P3388 割點】

【洛谷P3388 割點】

輸入格式 != 無向圖 from int oid == ++ 輸出格式

題目描述

  給出一個n個點,m條邊的無向圖,求圖的割點。

輸入格式:

  第一行輸入n,m

  下面m行每行輸入x,y表示x到y有一條邊

輸出格式:

  第一行輸出割點個數

  第二行按照節點編號從小到大輸出節點,用空格隔開

輸入樣例:

  6 7
  1 2
  1 3
  1 4
  2 5
  3 5
  4 5
  5 6

輸出樣例:

  1 
  5

說明

  n,m均為100000

  tarjan 圖不一定聯通!!!

題解

  裸的tarjan模板。一個點為割點:1.不為根節點且dfn[now]<=low[e[i].to] 2.為根節點且有超過兩個子樹

 1 #include<iostream>
 2
#include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 struct node 7 { 8 int next,to; 9 } e[200005]; 10 int head[100005],cut[100005],cnt=1,from[100005]; 11 int dfn[100005],low[100005],time; 12 inline void insert(int u,int v) 13 { 14 e[++cnt].next=head[u]; 15 head[u]=cnt;
16 e[cnt].to=v; 17 } 18 inline void tarjan(int now,int rt) 19 { 20 int num=0; 21 dfn[now]=low[now]=++time; 22 for(int i=head[now];i;i=e[i].next) 23 { 24 if(i==(from[now]^1)) continue; 25 if(!dfn[e[i].to]) 26 { 27 from[e[i].to]=i; 28 tarjan(e[i].to,rt);
29 low[now]=min(low[now],low[e[i].to]); 30 if(dfn[now]<=low[e[i].to] && now!=rt) cut[now]=1; 31 if(now==rt) num++; 32 } 33 else low[now]=min(low[now],dfn[e[i].to]); 34 } 35 if(now==rt && num>=2) cut[now]=1; 36 } 37 int main() 38 { 39 int n,m,u,v,ans=0; 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=m;i++) 42 { 43 scanf("%d%d",&u,&v); 44 insert(u,v); 45 insert(v,u); 46 } 47 for(int i=1;i<=n;i++) 48 if(!dfn[i]) tarjan(i,i); 49 for(int i=1;i<=n;i++) if(cut[i]) ans++; 50 printf("%d\n",ans); 51 for(int i=1;i<=n;i++) if(cut[i]) printf("%d ",i); 52 return 0; 53 }

【洛谷P3388 割點】