zoukankan      html  css  js  c++  java
  • 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的默认排序是从小到大。

  • 相关阅读:
    C#中 @ 的用法
    ASP.NET页面间传值
    ASP.NET中常用的文件上传下载方法
    把图片转换为字符
    把图片转换为字符
    JavaScript 时间延迟
    Using WSDLs in UCM 11g like you did in 10g
    The Definitive Guide to Stellent Content Server Development
    解决RedHat AS5 RPM安装包依赖问题
    在64位Windows 7上安装Oracle UCM 10gR3
  • 原文地址:https://www.cnblogs.com/zhuqiwei-blog/p/8552755.html
Copyright © 2011-2022 走看看