• 基环树上求环


    题目描述

    A subway scheme, classic for all Berland cities is represented by a set of n stations connected by n passages, each of which connects exactly two stations and does not pass through any others. Besides, in the classic scheme one can get from any station to any other one along the passages. The passages can be used to move in both directions. Between each pair of stations there is no more than one passage.

    Berland mathematicians have recently proved a theorem that states that any classic scheme has a ringroad. There can be only one ringroad. In other words, in any classic scheme one can find the only scheme consisting of stations (where any two neighbouring ones are linked by a passage) and this cycle doesn't contain any station more than once.

    This invention had a powerful social impact as now the stations could be compared according to their distance from the ringroad. For example, a citizen could say "I live in three passages from the ringroad" and another one could reply "you loser, I live in one passage from the ringroad". The Internet soon got filled with applications that promised to count the distance from the station to the ringroad (send a text message to a short number...).

    The Berland government decided to put an end to these disturbances and start to control the situation. You are requested to write a program that can determine the remoteness from the ringroad for each station by the city subway scheme.

    题目大意:求基环树上和环之间的最短距离。

    输入输出格式

    输入格式:

    The first line contains an integer n (3 ≤ n ≤ 3000), n is the number of stations (and trains at the same time) in the subway scheme. Then n lines contain descriptions of the trains, one per line. Each line contains a pair of integers xi, yi (1 ≤ xi, yi ≤ n) and represents the presence of a passage from station xi to station yi. The stations are numbered from 1 to n in an arbitrary order. It is guaranteed thatxi ≠ yi and that no pair of stations contain more than one passage. The passages can be used to travel both ways. It is guaranteed that the given description represents a classic subway scheme.

    输出格式:

    Print n numbers. Separate the numbers by spaces, the i-th one should be equal to the distance of the i-th station from the ringroad. For the ringroad stations print number 0.

    题解

    基环树:又称环套树,指的是由n个点和n条边组成的任意两点间都连通的图,比树多一条边,所以整个图中有且只有一个环。

    在基环树上找环,我们可以通过一边DFS,在遍历过程中对于一条边所到达的点已经被访问过,且不是这条边的出发点则证明这条边在环上。而这条边的终点V上一次到这一次之间所经过的点连成路径便是一个环,而这个路径们可以通过栈来记录。

    值得注意的是,一遍DFS只能求出一个环,而再求出环之后的DFS需要把这个环缩成一个点之后才能正常进行,这也是这个方法比较低效的方法。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAX = 3005;
    int Head[MAX], Next[MAX << 1], To[MAX << 1], w[MAX << 1], edgenum = 0;
    void Add_edge(int from, int to)
        {
            Next[++ edgenum] = Head[from];
            Head[from] = edgenum;
            To[edgenum] = to;
        }
    
    int sta[MAX], top = 0, vis[MAX], huan[MAX], cnthuan = 0, flag;
    void Get_huan(int u, int father)
        {
            if(flag) return;
            sta[++ top] = u, vis[u] = 1;
            for(int i = Head[u]; i != -1; i = Next[i])
            {
                int v = To[i];
                if(v == father)    continue;
                if(vis[v])    //有环
                {
                    huan[v] = ++cnthuan;
                    for(;sta[top] != v; -- top)    huan[sta[top]] = cnthuan;
                    top --;
                    flag = 1;
                    return;
                }
                Get_huan(v, u);
                sta[-- top], vis[v] = 0;
            }
            return;
        }
    
    int Deep[MAX];
    void Get_Deep(int u)
        {
            for(int i = Head[u]; i != -1; i = Next[i])
            {
                int v = To[i];
                if(Deep[v] || huan[v])    continue;
                Deep[v] = Deep[u] + 1;
                Get_Deep(v);
            }
        }
    
    int main()
    {
        //freopen("CF131D.in", "r", stdin);
        //freopen("CF131D.out", "w", stdout);
    
        int n, x, y, colorhuan;
        memset(Head, -1, sizeof(Head));
        scanf("%d", &n);
        for(int i = 1; i <= n; ++ i)
        {
            scanf("%d%d", &x, &y);
            Add_edge(x, y);
            Add_edge(y, x);
        }
        flag = 0;
        Get_huan(1, 0);
        for(int i = 1; i <= n; ++ i)
        {
            if(huan[i] != 0)
            {
                Deep[i] = 0;
                Get_Deep(i);
            }
        }
        for(int i = 1; i <= n; ++ i)    printf("%d ", Deep[i]);
        printf("
    ");
    }
  • 相关阅读:
    Qt5.3.2(VS2010)_调试_进入Qt源码
    Qt5.3.2(VS2010)_调试_遇到的问题
    Qt_QString::split测试
    Qt_QString.indesOf和mid测试
    激活_目标窗口
    DrawDibDraw__ZC测试
    【转】DrawDibDraw
    数学运算_基本_01
    get和post请求及进程和线程及cookie和session的区别
    Redis性能优化之redis.cnf配置文件
  • 原文地址:https://www.cnblogs.com/2020pengxiyue/p/9367819.html
Copyright © 2020-2023  润新知