开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第34天,点击查看活动详情
承接昨天复习完树的重心和树与图的深度和宽度优先遍历,之和来写这篇题解,emm,似乎可以说是为了写这个题解去听的课??? 进入正题:
[蓝桥杯 2013 省 A] 大臣的旅费
题目描述
很久以前,T 王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
为节省经费,T 国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J 是 T 国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。他有一个钱袋,用于存放往来城市间的路费。
聪明的 J 发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第 千米到第 千米这一千米中( 是整数),他花费的路费是 这么多。也就是说走 千米花费 ,走 千米要花费 。
J 大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入格式
输入的第一行包含一个整数 ,表示包括首都在内的 王国的城市数。
城市从 开始依次编号, 号城市为首都。
接下来 行,描述 国的高速路( 国的高速路一定是 条)。
每行三个整数 ,表示城市 和城市 之间有一条高速路,长度为 米。
输出格式
输出一个整数,表示大臣J最多花费的路费是多少。
样例 #1
样例输入 #1
5
1 2 2
1 3 1
2 4 5
2 5 4
样例输出 #1
135
提示
样例解释:大臣 J 从城市 到城市 要花费 的路费。
时限 5 秒, 64M。蓝桥杯 2013 年第四届省赛
分析
这题可以说是一个比较显然的题,为什么这么说呢,因为这是个板子题,因为只要知道树的直径,这题可以说是一个很好写的题目啦,这题说了这么多其实就是求树的直径为什么呢,因为树是一个无环连通图,树的直径就是树上两点最长距离,那么树的直径怎么球呢,分下面两步。
在树上随便找一点,然后找距离它距离最大的点,记作
从出发,找到距离距离最大的点,那么这个距离就是树的直径。
那么怎么证明呢,我们可以这么证明,只要证明是直径的端点,那么我们就可以证明是直径,那么怎么证明是端点呢,我们可以用反证法,设不是一个直径的端点。我们回到第一个过程,假设我们选这个点,我们假定树存在一条直径,端点分别为和。
假设和有交点为,因为是到距离最大的点之一,所以一定,所以,所以,所u到m必然也是一条直径,所以与假设不符合,故是一条直径的端点。
假设假设和没有交点,不妨在上取一点,上取一点,连接,同理显然可以发现,那么显然,,故到必然也是一条直径,与假设不符合,故是一条直径的端点。
于是乎,我们可以找到解题方法,通过两次找到树的直径,最后通过等差数列求和公式就可以把答案求出来了。 代码如下:
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#define pb push_back
#define ll long long
using namespace std;
const int N=100010;
int n;
struct edge{
int id,w;
};
ll dist[N];
vector<edge> h[N];
inline void dfs(int u,int father,int distance){
dist[u]=distance;
for(auto node:h[u]){
if(node.id!=father){
dfs(node.id,u,distance+node.w);
}
}
}
int main(){
cin>>n;
while(n--){
int a,b,c;
cin>>a>>b>>c;
h[a].pb({b,c});
h[b].pb({a,c});
}
dfs(1,-1,0);
int u=1;
for(int i=1;i<=n;i++){
if(dist[i]>dist[u]){
u=i;
}
}
dfs(u,-1,0);
for(int i=1;i<=n;i++){
if(dist[i]>dist[u]){
u=i;
}
}
ll s=dist[u];
cout<<(21+s)*s/2<<endl;
}
希望对大家有所帮助,