PAT-A 1021 Deepest Root (25)

  DFS 遍历无向图;计算树的深度;计算连通分量个数。

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.

Problem: PAT-A 1021 Deepest Root

Input Specification

Each input file contains one test case. For each case, the first line contains a positive integer N (≤ $10^4$) 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

1
2
3
4
5
5
1 2
1 3
1 4
2 5

Sample Output 1

1
2
3
3
4
5

Sample Input 2

1
2
3
4
5
5
1 3
1 4
2 5
3 4

Sample Output 2

1
Error: 2 components

Analysis

  判断无向图能否构成树结构,即是否为连通图、不成环。判断方法为计算无向图连通分量个数,如果大于 1 则为非连通图,输出错误提示。

  使用两次 DFS 遍历无向图。第一次遍历选择任意结点作为树根,搜索到当前最深层的叶子结点,同时记录深度相同的叶子结点。第二次遍历,选择第一次遍历解集中的任意结点(最深层的叶子反过来也可以作为树根)作为根结点,获得第二次遍历的解集。两次遍历的解集取并集,使用 set 保存解集,去重并自动排序。

  第一次遍历使用任意结点作为树根得出的最深层数不一定为最深。例如样例 1 从结点 1 开始遍历,获得最深层数为 3,即 1 -> 2 -> 5,而以 5 为树根进行遍历最深层数为 4,即 5 -> 2 -> 1 -> 3(4)。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
using namespace std;
const int mxN = 1e4 + 5;

vector<int> G[mxN], tmp; // 无向图, 临时解集
vector<bool> vis(mxN);

int max_h = 0;

void dfs(int idx, int h) {
vis[idx] = true;
if (h > max_h) {
max_h = h;
tmp.clear();
tmp.push_back(idx);
} else if (h == max_h) {
tmp.push_back(idx);
}

// 搜索当前结点所有子结点
for (auto it = G[idx].begin(); it != G[idx].end(); it++) {
if (vis[*it]) continue;
dfs(*it, h + 1);
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int N;
cin >> N;
for (int i = 1; i < N; i++) {
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}

int K = 0; // 统计连通分量
for (int i = 1; i <= N; i++) {
if (!vis[i]) {
dfs(i, 0);
K++;
}
}

if (K > 1) { // 连通分量大于 1, 非连通图, 输出错误
cout << "Error: " << K << " components" << endl;
return 0;
}

// 保存第一次深搜的解集
set<int> ans(tmp.begin(), tmp.end());

// 第二次深搜
fill(vis.begin(), vis.begin() + N + 1, false);
dfs(tmp[0], 0);

// 保存第二次深搜的解集
for (auto it = tmp.begin(); it != tmp.end(); it++) {
ans.insert(*it);
}
for (auto it = ans.begin(); it != ans.end(); it++) {
cout << *it << endl;
}
}

Tsukkomi

  没什么好吐槽的,继续学习。


#
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×