1021 Deepest Root

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;
}

题目链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值