1021 Deepest Root
题意描述
给出多个结点 求哪个结点做根结点时图的高度最高
输入输出格式
数据规模
结点的个数小于等于 1e4
算法设计
一种解法是枚举每个结点 求每个结点做根节点时图的最大高度 即从根节点出发做DFS(gg u, gg depth)
求得参数depth
最大
另一种解法是使用图的直径。图的直径是指图中任意两点之间最短距离的最大值 直径有许多性质 直径能够有多条 直径的两端有多个点 从任意一点开始进行DFS 能够到达的最大深度节点一定是直径的一端,当然 相同深度的节点可能有多个 它们都是直径的一端 然后 从直径的任意一端出发进行DFS 能够到达的最大深度节点一定是图的直径的另一端 由此 边引出了直径的求法 即进行两次DFS 一次DFS从任意一个点出发,到达直径的一端,再由这端开始DFS 到达直径的另一端 这个深度就是图直径的大小
当然 这里就是要求图直径端点的集合 只要直径端点做根节点 树的高度一定最大
c++11代码
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
const gg maxn = 1e4 + 10;
vector<vector<gg>>adj(maxn);
vector<gg>ufs(maxn);
vector<bool>flag(maxn);
vector<gg>tmp;
void init(){
iota(ufs.begin(),ufs.end(),0);
}
gg findFather(gg x){
return x == ufs[x] ? x : ufs[x] = findFather(ufs[x]);
}
void unionSets(gg x, gg y){
gg a = findFather(x), b = findFather(y);
if(a != b) ufs[a] = b;
}
void DFS(gg u, gg depth, gg& maxDepth){ // 这里 maxDepth 一定要引用 不然会导致反复更新 或者 全局变量
flag[u] = true;
if(depth > maxDepth){
tmp.clear();
maxDepth = depth;
}
if(maxDepth == depth) tmp.push_back(u);
for(auto i : adj[u]) if(not flag[i]) DFS(i,depth + 1,maxDepth);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
init();
gg n,u,v;
cin>>n; // 这里的树可以理解为一张无向图
for(gg i=0;i<n-1;i++){
cin>>u>>v;
adj[u].push_back(v);
adj[v].push_back(u);
unionSets(u,v);
}
unordered_map<gg,gg>um;
for(gg i=1;i<=n;i++) um[findFather(i)]++;
if(um.size() != 1) {
cout<<"Error: "<<um.size()<<" components";
return 0;
}
set<gg>res; // 这个结果是可能重复的 这里使用set 去重
gg maxDepth = -1;
DFS(1,1,maxDepth);
for(auto i : tmp) res.insert(i);
fill(flag.begin(),flag.end(),false);
tmp.clear();
maxDepth = -1;
DFS(*res.begin(),1,maxDepth);
for(auto i : tmp) res.insert(i);
for(auto i : res) cout<<i<<"\n";
return 0;
}