模擬考 T3 Tree
阿新 • • 發佈:2018-11-30
Description
Fanvree很聰明,解決難題時他總會把問題簡單化。例如,他就整天喜歡把圖轉化為樹。但是他不會縮環,那他怎麼轉化呢? 這是一個有n個點m條雙向邊的圖,Fanvree會選定一個節點,然後刪掉這個節點和這個點連出去的邊,如果變成了一棵樹,那麼這個節點便是可行的,什麼是樹呢?樹也即無簡單環的無向連通圖。告訴Fanvree可能的節點是什麼。
Input
第一行兩個正整數n和m,表示有n個點m條邊,保證n≥2。接下來m行,每行兩個整數v,u,表示v和u之間有一條無向邊1≤v,u≤n,保證沒有重邊和自環。
Output
第一行一個正整數ns,表示這個圖中有ns個結點可選。接下來一行,共ns個整數,每個整數表示一個可選結點的編號。請按編號從小到大的順序輸出。資料保證圖中至少存在一個可選的結點。
Hint
對於40%的資料:n,m<=1000; 另外存在10%的資料:m=n-1; 另外存在20%的資料:m=n; 對於100%的資料:n,m<=100000。
Solution
預處理出割點,統計每個點的度,如果m-這個點的度==n-2並且這個點不是割點,那麼它就可以刪。
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #define maxn 200005 using namespace std; struct Edge{ int u; int v; int next; int id; }edge[maxn]; int first[maxn],last[maxn],low[maxn],dfn[maxn],du[maxn],ans[maxn]; int node,n,m,x,y,dfn_TimeClock,cnt; bool vis[maxn],cut[maxn]; void addedge(int u,int v,int id){ edge[++node]=(Edge){u,v,0,id}; if(first[u]==0)first[u]=node; else edge[last[u]].next=node; last[u]=node; } void init(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); du[x]++; du[y]++; addedge(x,y,i); addedge(y,x,i); } } void Tarjan_h(int i,int fd){ vis[i]=true; dfn[i]=low[i]=++dfn_TimeClock; int xxx=0; for(int p=first[i];p;p=edge[p].next){ int j=edge[p].v,id=edge[p].id; if(vis[j]){ if(dfn[j]<dfn[i]&&id!=fd){ low[i]=min(low[i],dfn[j]); } continue; } xxx++; Tarjan_h(j,id); low[i]=min(low[i],low[j]); if(low[j]>=dfn[i])cut[i]=1; } if(xxx==1&&fd==0)cut[i]=0; } void workk(){ Tarjan_h(1,0); for(int i=1;i<=n;i++){ if(m-du[i]==n-2&&!cut[i]){ ans[++cnt]=i; } } } int main(){ init(); workk(); printf("%d\n",cnt); for(int i=1;i<=cnt;i++){ printf("%d ",ans[i]); } printf("\n"); return 0; }