PAT-A 真题- 1021. Deepest Root

发布于 / PAT-甲级 / 0 条评论

原题干:

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

题目大意:第一行给出图的顶点个数,接下来给出N-1行数据,每行两个正整数,代表这两个正整数代表的顶点是连接的

要求判断这个图是不是一个连通块。如果不是一个连通块,输出错误信息,并说明有几个连通块。如果是一个连通块,则判断这些顶点能表示的最大高度的树,有几种可能的根,并按照顺序输出(要保持顶点的连接状况)(博主语文不好,只能说成这样了)

这道题判断连通块可以使用并查集,亦可使用DFS。这里博主用的是DFS。至于找出最高的树的根,《算法笔记》上给出了一种很好的办法:

先随机找一个节点,沿着节点遍历,找到能到达最大高度的所有节点(记做集合A),接着在集合A中随机找一个节点,沿着它遍历,找到能到达的所有节点(记做集合B),这时,集合A和集合B就是所求树根的集合。

至于为什么,其实也很好理解。随机找一个节点,可能是中间的某个节点;遍历得到的集合A,是这个节点能到达的最大高度。所以A一定是一个"边缘性节点",最大高度的树一定是"边缘性节点到边缘性节点",而不可能是中间的某个节点。沿着A中的任意元素进行遍历,找到的集合B一定还是边缘性节点,故两者都是最大高度的树的根。(博主语文不好。。。只能讲成这样了

至于排序去重,我们这里可以使用set容器来完成。代码里面有很详细的注释:

#include <iostream>
#include <vector>
#include <set>
using namespace std;
#define MAXN 10010
/**
 * 全局变量区
 * G为邻接表,tmp为存储临时结果的容器
 * visited为标记数组,nodes_sum为节点总数,max_depth存放最大高度
 */
vector<int> G[MAXN], tmp;
bool visited[MAXN] = {false};
int nodes_sum, max_depth = 0;
/**
 * 深度优先搜索方法
 * 参数:起始节点、深度
 */
void DFS(int start, int depth){
    if(depth > max_depth){  //如果深度大于最大深度
        tmp.clear();        //清空临时容器
        tmp.push_back(start);//将当前顶点压入容器
        max_depth = depth;  //更新最大深度值
    }else if(depth == max_depth) tmp.push_back(start);  //如果深度等于最大深度,将当前节点压入容器
    visited[start] = true;  //标记当前访问的节点为"已访问"
    for(int i = 0; i < G[start].size(); i++){
        int next = G[start][i];//下一个节点的编号
        if(!visited[next]) DFS(next, depth + 1);    //递归访问下一个节点
    }
}
/**
 * 计算连通块的方法
 * 返回:连通块数量
 */
int calBlock(){
    int cnt = 0;
    for(int i = 1; i <= nodes_sum; i++){
        if(!visited[i]){
            cnt++;
            DFS(i, 1);
        }
    }
    return cnt;
}

int main(){
    cin >> nodes_sum;   //读入节点数量
    for(int i = 1; i < nodes_sum; i++){ //依次读入顶点
        int tmp1, tmp2;
        cin >> tmp1 >> tmp2;
        G[tmp1].push_back(tmp2);
        G[tmp2].push_back(tmp1);    //写入邻接表
    }
    int block_sum = calBlock();     //计算连通块数量
    if(block_sum > 1){              //连通块数量大于1,输出错误信息,退出
        cout << "Error: " << block_sum << " components" << endl;
        exit(0);
    }
    set<int> result;                //存放结果的set容器
    for(int i = 0; i < tmp.size(); i++) result.insert(tmp[i]);  //将当前结果存入容器病自动排序
    fill(visited, visited + nodes_sum + 1, false);      //刚刚DFS已经污染了visited,这里要重新赋值
    DFS(tmp[0], 1);                 //遍历
    for(int i = 0; i < tmp.size(); i++) result.insert(tmp[i]);  //存入容器并排序
    for(set<int>::iterator i = result.begin(); i!= result.end(); i++){  //枚举输出
    cout << *i << endl;
  }
    return 0;
}

转载原创文章请注明,转载自: 斐斐のBlog » PAT-A 真题- 1021. Deepest Root
目前还没有评论,快来抢沙发吧~