题目描述
很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。
聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。
J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入
输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数
城市从1开始依次编号,1号城市为首都。
接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)
每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。
输出
输出一个整数,表示大臣J最多花费的路费是多少。
样例输入
5
1 2 2
1 3 1
2 4 5
2 5 4
样例输出
135
提示
输出格式
大臣J从城市4到城市5要花费135的路费。
思路:刚开始看到这道题第一想法是用dij()来求最长路径,但是到后来发现是求任意两点最长的距离。随后我有参考别人的代码,思路都是要用两遍DFS,即第一次找出最长路的一个端点,第二次便是从最长路的一个端点dfs出最长路;可能会有人问为什么这样求出来的距离就是两点之间最长的,下面给出证明的思路:
树的直径也就是最长路的证明:
假设 s-t这条路径为树的直径,或者称为树上的最长路
现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路
证明:
1 设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T则
dis(u,T) >dis(u,s) 且 dis(u,T)>dis(u,t) 则最长路不是s-t了,与假设矛盾
2 设u不为s-t路径上的点
首先明确,假如u走到了s-t路径上的一点,那么接下来的路径肯定都在s-t上了,而且终点为s或t,在1中已经证明过了
所以现在又有两种情况了:
1:u走到了s-t路径上的某点,假设为X,最后肯定走到某个端点,假设是t ,则路径总长度为dis(u,X)+dis(X,t)
2:u走到最远点的路径u-T与s-t无交点,则dis(u-T) >dis(u,X)+dis(X,t);显然,如果这个式子成立,
则dis(u,T)+dis(s,X)+dis(u,X)>dis(s,X)+dis(X,t)=dis(s,t)最长路不是s-t矛盾
找出来最长的路径,就可以用DFS来算出所需的费用了,下面附上AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
struct node
{
int now, cost;
};
vector<node>S[10010];
int vis[10010];
int a, b, c, n;
int temp;
long long ans = -99999;
void dfs(int s, int dist)
{
if(ans < dist)
ans = dist, temp = s;
for(int i = 0; i < S[s].size(); i++)
{
node p = S[s][i];
if(!vis[p.now]&&p.cost)
{
vis[p.now] = 1;
dist+=p.cost;
dfs(p.now, dist);
vis[p.now] = 0;
dist-=p.cost;
}
}
return ;
}
int main()
{
cin >> n;
node p;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++)
S[i].clear();
for(int i = 0; i < n - 1; i++)
{
cin >> a >> b >>c;
p.now = b;
p.cost = c;
S[a].push_back(p);
p.now = a;
S[b].push_back(p);
}
vis[1] = 1;
dfs(1, 0);
memset(vis, 0, sizeof(vis));
vis[temp] = 1;
ans = -99999;
dfs(temp, 0);
printf("%d \n", ((11+10+ans)*ans)/2);
return 0;
}