基环树(基环树)

题目描述:
基环树是比一棵树多一条非树边的图,他具有很多的性质。现在给出一颗基环树,请输出这颗基环树中的环上的点,按字典序最小的顺序输出。

输入格式:
第1行包含2个正整数N,表示有N个点。
第2~N+1行包含2个用空格隔开的正整数u,v,表示一条从u到v的无向路径。保证给出的是一棵基环树。

输出格式:
输出若干个数字,表示这棵基环数上的环的点,按字典序最小的顺序输出。

样例1输入:

5
1 2
1 3
1 5
3 4
4 2
样例1输出:
1 3 4 2
约定:
1≤N≤106

本场比赛的第二道假题

样例的图是上面的那张,显然1243字典序最小……所以题目的意思是逆时针,字典序最小

hack完题目,然后讲基环树:

一直跑dfs,跑到一个已经出现过的点就代表出现环(不然在树上跑是不会有这种情况的)。跑到环记录一下就好了。记录环好像不是很好理解,跟这样例手动模拟一遍就懂了qwq

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
int n,dfn[N],idx,fa[N],tot,ans[N],start,tmp=1000000007;
vector<int>g[N];
void get(int u)
{
    dfn[u]=++idx;
    for(int i=0;i<g[u].size();++i)
    {
        int v=g[u][i];
        if(v==fa[u])continue;
        if(!dfn[v])fa[v]=u,get(v);
        else
        {
            if(dfn[v]<dfn[u])continue;
            ans[++tot]=v;
            while(v!=u)
            {
                v=fa[v];
                ans[++tot]=v;
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1,x,y;i<=n;++i)
        scanf("%d%d",&x,&y),g[x].push_back(y),g[y].push_back(x);
    get(1);
    for(int i=1;i<=tot;++i)if(tmp>ans[i])tmp=ans[i],start=i;
    for(int i=1;i<=tot;++i)ans[i+tot]=ans[i];
    for(int i=start;i<=tot+start-1;++i)printf("%d ",ans[i]);
    return 0;
     
}

猜你喜欢

转载自www.cnblogs.com/zzctommy/p/12322180.html