【NOIP提高】种树

来源:互联网 发布:2017年人工智能股票 编辑:程序博客网 时间:2024/05/18 00:38

Description

这里写图片描述

Solution

删点的前提条件

首先,一棵树有n个节点,就有n-1条边。
那么删掉这个点之后,必须满足n-1个点,n-2条边。

奇怪的情况

如果你删掉了这个点,把原来的这个图分成了两个部分,那么这个点就不能删掉。
怎么找这个点。
其实这种点叫做割点。
一个割点满足,这个点连出的边,有一个点是在不同的强连通分量里面的话,那么这个点就是一个割点。
强连通分量要用tarjan求。
由于每条边只会被访问两次,所以找割点的速度是O(m)的。
所以删掉的这个点要满足前提条件,还不能是割点。

特殊的情况

如果原图本来就是一棵树,那么就只用删掉叶子节点。

Code

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)#define rep(i,a) for(i=first[a];i;i=next[i])using namespace std;const int maxn=100007;int i,j,k,l,t,n,m,ans[maxn];int a[maxn],u,v,p,q,ans1;int first[maxn*2],last[maxn*2],next[maxn*2],num;bool bz[maxn],az[maxn],dz[maxn],cz[maxn*2];int cnt[maxn],f[maxn][21],deep[maxn],sh[maxn];int dfn[maxn],low[maxn],stack[maxn],df;int op[maxn],ans2[maxn];void add(int x,int y){    last[++num]=y;next[num]=first[x];first[x]=num;}void tarjan(int x){    int i,j,k;    dfn[x]=low[x]=++df;    stack[++stack[0]]=x;    bz[x]=az[x]=1;    rep(i,x){        if(cz[(i+1)/2])continue;        cz[(i+1)/2]=1;        if(!bz[last[i]]){            tarjan(last[i]);            low[x]=min(low[x],low[last[i]]);        }        else if(az[last[i]]){            low[x]=min(low[x],dfn[last[i]]);        }    }    if(dfn[x]==low[x]){        int u=0;         while(stack[stack[0]+1]!=x){            az[stack[stack[0]]]=0;            op[++u]=stack[stack[0]];            stack[0]--;        }        if(u>ans2[0]){            memcpy(ans2,op,sizeof(ans2));            ans2[0]=u;        }    }}bool pan(int x){    int i;bool bz=1;    rep(i,x){        if(!dz[last[i]])bz=dz[last[i]];    }    return bz;}int main(){    scanf("%d%d",&n,&m);    fo(i,1,m){        scanf("%d%d",&k,&l);        a[l]++,a[k]++;        add(k,l);        add(l,k);    }    tarjan(1);    fo(i,1,ans2[0]){        dz[ans2[i]]=1;    }    if(m==n-1){        fo(i,1,n){            if(m-a[i]==n-2)ans[++ans[0]]=i;        }        printf("%d\n",ans[0]);        fo(i,1,ans[0])printf("%d ",ans[i]);        return 0;    }    fo(i,1,n){        if(pan(i)&&m-a[i]==n-2)ans[++ans[0]]=i;    }    printf("%d\n",ans[0]);    fo(i,1,ans[0])printf("%d ",ans[i]);}
1 0
原创粉丝点击