• A1021. Deepest Root


    A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.

    Input Specification:

    Each input file contains one test case. For each case, the first line contains a positive integer N (<=10000) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N-1 lines follow, each describes an edge by given the two adjacent nodes' numbers.

    Output Specification:

    For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print "Error: K components" where K is the number of connected components in the graph.

    Sample Input 1:

    5
    1 2
    1 3
    1 4
    2 5
    

    Sample Output 1:

    3
    4
    5
    

    Sample Input 2:

    5
    1 3
    1 4
    2 5
    3 4
    

    Sample Output 2:

    Error: 2 components

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<vector>
     4 #include<algorithm>
     5 using namespace std;
     6 int G[10001][10001];
     7 int father[10001];
     8 int maxDepth = -1;
     9 int N;
    10 vector<int> temp_, ans;
    11 void dfs(int vt, int from, int level){
    12     level++;
    13     if(maxDepth < level){
    14         maxDepth = level;
    15         temp_.clear();
    16         temp_.push_back(vt);
    17     }else if(maxDepth == level){
    18         temp_.push_back(vt);
    19     }
    20     for(int i = 1; i <= N; i++){
    21         if(G[vt][i] == 1 && i != from){
    22             dfs(i, vt, level);
    23         }
    24     }
    25 }
    26 int findFather(int vt){
    27     int temp = vt;
    28     while(vt != father[vt]){
    29         vt = father[vt];
    30     }
    31     int temp2;
    32     while(temp != vt){
    33         temp2 = father[temp];
    34         father[temp] = vt;
    35         temp = temp2;
    36     }
    37     return vt;
    38 }
    39 int main(){
    40     scanf("%d", &N);
    41     int tempA, tempB;
    42     int root1, root2;
    43     for(int i = 1; i <= N; i++){
    44         father[i] = i;
    45     }
    46     for(int i = 0; i < N - 1; i++){
    47         scanf("%d%d", &tempA, &tempB);
    48         G[tempA][tempB] = G[tempB][tempA] = 1;
    49         root1 = findFather(tempA);
    50         root2 = findFather(tempB);
    51         if(root1 != root2)
    52             father[root2] = root1;
    53     }
    54     int cnt = 0;
    55     for(int i = 1; i <= N; i++){
    56         if(father[i] == i)
    57             cnt++;
    58     }
    59     if(cnt > 1){
    60         printf("Error: %d components
    ", cnt);
    61     }else{
    62         maxDepth = -1;
    63         dfs(1, -1, 0);
    64         ans = temp_;
    65         temp_.clear();
    66         maxDepth = -1;
    67         dfs(ans[0], -1, 0);
    68         for(int i = 0; i < temp_.size(); i++)
    69             ans.push_back(temp_[i]);
    70         sort(ans.begin(), ans.end());
    71         printf("%d
    ", ans[0]);
    72         for(int i = 1; i < ans.size(); i++){
    73             if(ans[i] != ans[i - 1])
    74                 printf("%d
    ", ans[i]);
    75         }
    76     }
    77     cin >> N;
    78     return 0;
    79 }
    View Code

    总结:

    1、题意:给出一个可能是树的图,要求找到root(可能多个),使得从root出发可以使树的高度最高。但如果给出的图不是树(因为N个顶点 N - 1条边,如果产生回路只能说明输入的图不是一个连通图),要求输出连通分量的个数。 起初没注意到N个节点 N - 1条边这个条件,没有搞清楚题意,还以为判断是否是树是通过判断图里有没有回路来进行的,莫名奇妙为什么不是树之后就要求联通分量。于是还通过找回路来判断是否是树,结果当然不对。

    2、求连通分量首选并查集,如果两个点是联通的就把它们并为一个集合。在读入边的时候就可以做合并,结束之后计数father[ i ] = i 的节点个数就行了。其次可以借助深搜广搜配合visit数组,在遍历完每一个点,检查下一个点的visit为0的即作为一个连通分量。显然,当输入的图连通分量大于1时说明不是树。

    3、找能使得树最高的root方法:先随便找一个点A,从它开始做一遍dfs并在过程中将level最大的节点全部保存。这些节点就是答案的一部分,但还存在遗漏。再从已经选出的root中随意选择一个B,从它开始遍历一遍dfs并保存level最大的节点,两部分并起来就是最终答案。(没看书之前我是暴力破解,把所有节点遍历一次以找到最大深度的根,结果有一个测试点超时)

    4、visit数组:平时做bfs使用visit数组标记节点是否曾经加入过队列,做dfs标记节点是否被访问过,其实都是为了防止重复访问节点。但本题中一旦确定了是一棵树,说明不存在回路,则可以不需要visit数组。但在无向图中仍然需要一个变量保存上一次访问过的节点,以防止同一条边上的重复访问。比如节点A、B在一条边上,A->B访问结束,到B之后B的联通的节点中又会有A,造成再次访问A(用孩子法存储的树无需考虑该问题,但用图的形式存储的树必须考虑同一条边的重复访问)。

    5、找回路:利用visit数组与上次访问节点的序号即可。在碰到一个与当前节点相连接、不是上一次访问过的再同一条边上的节点、visit数组为1,则存在回路。

    6、sort的默认排序是从小到大。

  • 相关阅读:
    Shell脚本编程-02-----shell编程之条件语句
    ELK 简介
    Linux 下的网卡文件配置
    Tomcat 简介
    Docker 基本操作
    zabbix 介绍
    CentOS 上搭建 Kubernetes 集群
    Docker 简介
    yum 源的配置安装
    Docker 入门
  • 原文地址:https://www.cnblogs.com/zhuqiwei-blog/p/8552755.html
Copyright © 2020-2023  润新知