PAT 甲级1021 Deepest Root
给定N个节点和N-1条边,找到其中的最深根节点——该根节点使整个树的深度最大
先判断该图是否是一颗树,即判断连通分量个数,如果连通分量个数大于1,则说明出现了循环图,不能构成树
如果联通分量为1,就要找最深根节点,需要两次dfs。
第一次dfs从任意节点出发,**找到深度最大的叶子节点们,**然后从这些叶子节点中任意选择一个,开始dfs,再次找到深度最大的叶子节点们。
最终结果是两次dfs结果的 并集——使用set
// 1021 Deepest Root.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
int n, maxheight = 0;
vector<vector<int>> v; //记录每个节点的邻接节点
bool visit[10010]; //记录dfs中每个节点的访问情况
set<int> s; //并查集
vector<int> temp; //记录深度最大的节点
void dfs(int node, int height) {
if (height > maxheight) { //更新
temp.clear();
temp.push_back(node);
maxheight = height;
}
else if (height == maxheight) { //添加深度最大节点
temp.push_back(node);
}
visit[node] = true;
for (int i = 0; i < v[node].size(); i++) {
if (visit[v[node][i]] == false) { //因为是无向图,节点的邻接节点可能被访问过
dfs(v[node][i], height + 1);
}
}
}
int main()
{
cin >> n;
v.resize(n + 1);
int a, b, s1 = 0, cnt = 0;
for (int i = 0; i < n - 1; i++) {
cin >> a >> b;
v[a].push_back(b);
v[b].push_back(a);
}
for (int i = 1; i <= n; i++) {
if (visit[i] == false) {
dfs(i, 1);
if (i == 1) {
if (temp.size() != 0) s1 = temp[0]; //s1为第二次dfs的根节点
for (int j = 0; j < temp.size(); j++) {
s.insert(temp[j]); //将第一次dfs结果插入set
}
}
cnt++; //记录连通分量个数
}
}
if (cnt >= 2) printf("Error: %d components", cnt);
else {
temp.clear(); //清空temp,准备第二次dfs
maxheight = 0;
fill(visit, visit + 10010, false);
dfs(s1, 1);
for (int i = 0; i < temp.size(); i++) s.insert(temp[i]); //将第二次dfs结果插入set
for (auto it = s.begin(); it != s.end(); it++) {
cout << *it << endl; //输出结果
}
}
return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件