基环树上求环

题目描述

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需要把这个环缩成一个点之后才能正常进行,这也是这个方法比较低效的方法。

代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int MAX = 3005;
 5 int Head[MAX], Next[MAX << 1], To[MAX << 1], w[MAX << 1], edgenum = 0;
 6 void Add_edge(int from, int to)
 7     {
 8         Next[++ edgenum] = Head[from];
 9         Head[from] = edgenum;
10         To[edgenum] = to;
11     }
12
13 int sta[MAX], top = 0, vis[MAX], huan[MAX], cnthuan = 0, flag;
14 void Get_huan(int u, int father)
15     {
16         if(flag) return;
17         sta[++ top] = u, vis[u] = 1;
18         for(int i = Head[u]; i != -1; i = Next[i])
19         {
20             int v = To[i];
21             if(v == father)    continue;
22             if(vis[v])    //有环
23             {
24                 huan[v] = ++cnthuan;
25                 for(;sta[top] != v; -- top)    huan[sta[top]] = cnthuan;
26                 top --;
27                 flag = 1;
28                 return;
29             }
30             Get_huan(v, u);
31             sta[-- top], vis[v] = 0;
32         }
33         return;
34     }
35
36 int Deep[MAX];
37 void Get_Deep(int u)
38     {
39         for(int i = Head[u]; i != -1; i = Next[i])
40         {
41             int v = To[i];
42             if(Deep[v] || huan[v])    continue;
43             Deep[v] = Deep[u] + 1;
44             Get_Deep(v);
45         }
46     }
47
48 int main()
49 {
50     //freopen("CF131D.in", "r", stdin);
51     //freopen("CF131D.out", "w", stdout);
52
53     int n, x, y, colorhuan;
54     memset(Head, -1, sizeof(Head));
55     scanf("%d", &n);
56     for(int i = 1; i <= n; ++ i)
57     {
58         scanf("%d%d", &x, &y);
59         Add_edge(x, y);
60         Add_edge(y, x);
61     }
62     flag = 0;
63     Get_huan(1, 0);
64     for(int i = 1; i <= n; ++ i)
65     {
66         if(huan[i] != 0)
67         {
68             Deep[i] = 0;
69             Get_Deep(i);
70         }
71     }
72     for(int i = 1; i <= n; ++ i)    printf("%d ", Deep[i]);
73     printf("\n");
74 }

原文地址:https://www.cnblogs.com/2020pengxiyue/p/9367819.html

时间: 2024-12-20 03:21:54

基环树上求环的相关文章

如果单链表有环,求环的起始位置

问题:如果单链表中存在环,求环的起始位置 解:在上篇文章中,利用追逐法判断一个单链表是否存在环.求环的起始位置,需要求解单链表的长度和环的长度的关系.如果确定了单链表的长度和环的长度的关系,那么环的起始位置就呼之欲出了. 在判断单链表中有两个指针P和q,p每次前进两步,q每次前进一步,p的速度是q的两倍.设单链表的长度为L,环的长度为R,链表起点到环起点的距离为X,当p和q相遇时,慢指针总共走了S步,在环内总共走了a步,快指针总共走了2S步,此时满足:2S=S+n*R,所以S=n*R. S=X+

poj 2240 Bellman-Flod 求环

http://poj.org/problem?id=2240 深刻体现了自己代码能力有问题外加改模板能力有问题,外加Debug有问题.以后做到: 1.算法原理可以轻易弄出来, 2.代码模板自己收集各种用法,以及已经的做过的改变的方法: 3.没有完整清晰的思路不敲代码: 4.在Debug时没有基本绝对的把握,不点击"编译+运行",不乱试 回到这道题: 我主要是想把Bellman-Ford的模板改为链式前向星的,然后就各种悲剧调试...... 学到三点:1.比例的初始化,求最大,源1.0,

笔试,面试,C/C++,判断单链表是否带环?若带环,求环长度,求环入口点(两种方法)

SListNode* IsRing(SListNode *&pHead) //判断链表是否有环,求相聚点 {  //判空.有.没有  //思路:两个指针从头开始一快(2步)一慢(1步),若最后可以相聚,则链表有环  if (pHead)  {   SListNode *fast = pHead;   SListNode *slow = pHead;   while (fast&&fast->next)   {    fast = fast->next->next;

单链表的经典操作,查找链表倒数第k个节点,判断链表是否存在环,求环节点

#include<stdio.h>#include<stdlib.h> typedef struct date_list{    int data;    struct date_list* next;}mylist; mylist* creatlist(int x,mylist* p)        //用一个元素创建链表{    if(NULL == p)                         //链表创建必须判空    {        p = malloc(siz

POJ 题目2750 Potted Flower(线段树求环型区间中连续区间的最大和)

Potted Flower Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4470   Accepted: 1698 Description The little cat takes over the management of a new park. There is a large circular statue in the center of the park, surrounded by N pots of f

判断一链表是否有环,求环的第一个节点和环的长度

第一种方法:直接遍历时,用hashset存放,判断是否存在环 第二种方法:使用快慢指针 public class CycleLinkedList { public static void main(String[] args) { Node head = new Node(1); Node node3 = new Node(3); head.next = node3; head.next.next = new Node(5); head.next.next.next = new Node(7);

[算法整理]树上求LCA算法合集

1#树上倍增 以前写的博客:http://www.cnblogs.com/yyf0309/p/5972701.html 预处理时间复杂度O(nlog2n),查询O(log2n),也不算难写. 2#st表(RMQ) 首先对一棵树进行dfs,得到欧拉序列,记录下每个节点的第一次出现位置. (先序遍历这棵树,访问到的节点(无论是从深的一层返回还是父节点访问)就加入到序列中,序列长度为2 * n - 1) 根据欧拉序列神奇的特性,两个点第一次出现的位置之间,深度最小的一个点,是这两个点LCA(反正我是不

结对开发--求环数组的最大字数组

一.题目要求 题目:返回一个整数数组中最大子数组的和. 要求: 输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 如 果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大. 同时返回最大子数组的位置. 求所有子数组的和的最大值.要求时间复杂度为O(n). 二.设计思路 这次的主要问题在于这次的一位数组要首尾相连,允许A[i-1], …… A[n-1], A[0]……A[j-1]

关于用BFS求环的数量

简单说说的话就是循环里面套bfs.... oj 1196...... #include<iostream> #include<string> #include<cstring> #include<cstring> #include<cstring> using namespace std; int dx[9],dy[9]; int top=0; struct ww { int x,y,c,v; }q[10000000]; int big[1000