1. 程式人生 > >模擬考 T3 Tree

模擬考 T3 Tree

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;
}