大臣的旅费

77 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第34天,点击查看活动详情

承接昨天复习完树的重心和树与图的深度和宽度优先遍历,之和来写这篇题解,emm,似乎可以说是为了写这个题解去听的课??? 进入正题:

[蓝桥杯 2013 省 A] 大臣的旅费

题目描述

很久以前,T 王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T 国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J 是 T 国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的 J 发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第 xx 千米到第 x+1x+1 千米这一千米中(xx 是整数),他花费的路费是 x+10x+10 这么多。也就是说走 11 千米花费 1111,走 22 千米要花费 2323

J 大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式

输入的第一行包含一个整数 n(n105)n(n \le 10^5),表示包括首都在内的 TT 王国的城市数。

城市从 11 开始依次编号,11 号城市为首都。

接下来 n1n-1 行,描述 TT 国的高速路(TT 国的高速路一定是 n1n-1 条)。

每行三个整数 Pi,Q,DiP_i,Q,D_i,表示城市 PiP_i 和城市 QiQ_i 之间有一条高速路,长度为 Di(Di1000)D_i(D_i \le 1000) 米。

输出格式

输出一个整数,表示大臣J最多花费的路费是多少。

样例 #1

样例输入 #1

5
1 2 2
1 3 1
2 4 5
2 5 4

样例输出 #1

135

提示

样例解释:大臣 J 从城市 44 到城市 55 要花费 135135 的路费。

时限 5 秒, 64M。蓝桥杯 2013 年第四届省赛

分析

这题可以说是一个比较显然的题,为什么这么说呢,因为这是个板子题,因为只要知道树的直径,这题可以说是一个很好写的题目啦,这题说了这么多其实就是求树的直径为什么呢,因为树是一个无环连通图,树的直径就是树上两点最长距离,那么树的直径怎么球呢,分下面两步。

1.1.在树上随便找一点,然后找距离它距离最大的点,记作uu

2.2.uu出发,找到距离uu距离最大的点vv,那么这个距离就是树的直径。

那么怎么证明呢,我们可以这么证明,只要证明uu是直径的端点,那么我们就可以证明uvuv是直径,那么怎么证明uu是端点呢,我们可以用反证法,设uu不是一个直径的端点。我们回到第一个过程,假设我们选kk这个点,我们假定树存在一条直径yzyz,端点分别为yyzz

1.1.假设yzyzkuku有交点为mm,因为uu是到kk距离最大的点之一,所以ukuk一定km+mz≥km+mz,所以ummzum≥mz,所以um+myym+mz=yzum+my≥ym+mz=yz,所u到m必然也是一条直径,所以与假设不符合,故uu是一条直径的端点。

2.2.假设假设yzyzkuku没有交点,不妨在kuku上取一点aayzyz上取一点bb,连接abab,同理显然可以发现auab+bzau≥ab+bz,那么ua+abua+ab显然bz≥bzyb+ba+auyb+bz=yzyb+ba+au≥yb+bz=yz,故yyuu必然也是一条直径,与假设不符合,故uu是一条直径的端点。

于是乎,我们可以找到解题方法,通过两次dfsdfs找到树的直径,最后通过等差数列求和公式就可以把答案求出来了。 代码如下:

代码

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

希望对大家有所帮助,QAQ!QAQ!