#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6+9; // 表示最大王国数量
vector<int>vt[N],q; // 定义向量数组vt和q,用于存储相邻王国和征服顺序
ll deep[N],dis[N],du[N]; // 定义长整型数组deep、dis和du,分别表示深度、距离和度
bool cmp(int &a,int &b)
{
return dis[a]<dis[b]; // 返回距离较小的王国
}
void dfsx(int x,int fa) //用于计算每个王国的深度
{
dis[x] = deep[x]; // 初始化距离为深度
for(auto it:vt[x]) // 遍历相邻王国
{
if(it == fa)continue; // 如果相邻王国是父节点,跳过
deep[it] = deep[x] + 1; // 更新相邻王国的深度
dfsx(it,x); // 递归调用dfsx函数
dis[x] = max(dis[x],dis[it]); // 更新当前王国的距离
}
}
void dfsy(int x, int fa) // ,用于计算征服顺序
{
q.push_back(x); // 将当前王国加入征服顺序
sort(vt[x].begin(),vt[x].end(),cmp); // 根据距离对相邻王国进行排序
for(auto it:vt[x]) // 遍历相邻王国
{
if(it == fa)continue; // 如果相邻王国是父节点,跳过
dfsy(it,x); // 递归调用dfsy函数
q.push_back(x); // 将当前王国加入征服顺序
}
}
int main() // 主函数
{
int n,u,v; cin >> n; // 输入王国数量
for(int i = 1; i < n ; i++) // 输入相邻王国关系
{
cin >> u >> v;
vt[u].push_back(v);du[u]++;
vt[v].push_back(u);du[v]++;
}
dfsx(1,0); // 调用dfsx函数计算深度
dfsy(1,0); // 调用dfsy函数计算征服顺序
ll cnt = 1, ans = 0; // 初始化计数器和答案
for(auto i:q) // 遍历征服顺序
{
if(du[i] == 1) // 如果当前王国的度为1
{
ans += min(cnt,deep[i]);cnt = 0; // 更新答案并将计数器清零
}
cnt++; // 计数器加1
}
cout << ans << '\n'; // 输出答案
return 0; // 返回0,表示程序正常结束
}
下面来解释一些话:
dis[x] = max(dis[x],dis[it]);
表示取当前王国和相邻王国距离的最大值作为新的当前王国的距离。
可以确保当前王国的距离始终是其自身和相邻王国中距离最大的那个。这样可以保证在后续的征服顺序计算中,能够正确地选择距离最远的王国进行征服。
那为什么呢?
选择距离最远的王国进行征服,通常是为了优化征服的顺序,以便在有限的资源或时间内尽可能多地征服王国。这种策略背后的逻辑是,一旦你征服了距离最远的王国,你就可以确保你的王国与任何其他未被征服的王国之间的距离至少不会变得更远。
在图论和算法中,这通常与“最小生成树”或“最短路径”问题有关,其中目标是找到一种方式来连接所有节点(在这个场景中是王国),同时最小化总的距离或成本。在这种情况下,选择距离最远的王国进行征服可以帮助减少未来可能需要的移动次数,因为每次征服都会覆盖尽可能多的其他未征服王国。
在给定的代码中,dfsy
函数通过递归地调用自身来遍历图,并且每次递归都根据距离对相邻王国进行排序。这意味着在每一步,代码都会选择距离当前王国最远的王国作为下一个征服目标。这样做的目的是为了最大化每次征服的影响,从而在征服顺序结束时,总的距离尽可能地小。
这个问题涉及到图论中的深度优先搜索(DFS)和拓扑排序。在这个问题中,我们的目标是计算征服顺序,使得每个王国都能被征服,并且每次征服的都是距离最远的王国。
首先,我们需要理解为什么从最远的开始征服是最优的选择。假设我们有一组王国,其中一些王国之间的距离比其他王国更远。如果我们按照距离从小到大的顺序进行征服,那么在征服一个距离较近的王国时,可能会错过一些距离更远的王国,导致无法完全征服所有王国。而如果我们从最远的开始征服,那么我们可以确保在征服一个距离较近的王国之前,已经征服了所有距离更远的王国,从而避免了这种情况的发生。
其次,我们需要理解为什么可以通过深度优先搜索来计算每个王国的深度。在深度优先搜索中,我们从某个节点开始,沿着路径深入到不能再深入为止,然后回溯到上一个节点,继续深入其他路径。这样,我们可以确保每个节点的深度都是其到根节点的最短路径长度。因此,通过深度优先搜索,我们可以计算出每个王国的深度。
最后,我们需要理解为什么可以通过拓扑排序来计算征服顺序。在拓扑排序中,我们将所有的节点按照它们的依赖关系进行排序,使得对于任意两个节点u和v,如果存在一条从u到v的边,那么u一定在v之前。这样,我们可以确保在征服一个节点之前,已经征服了所有依赖于它的节点。因此,通过拓扑排序,我们可以计算出征服顺序。
综上所述,从最远的开始征服可以确保我们能够完全征服所有王国,而通过深度优先搜索和拓扑排序,我们可以准确地计算出每个王国的深度和征服顺序。