很久以前,T 王国空前繁荣。
为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
为节省经费,T 国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。
同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J 是 T 国重要大臣,他巡查于各大城市之间,体察民情。
所以,从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。
他有一个钱袋,用于存放往来城市间的路费。
聪明的 J 发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关。
具体来说,一段连续的旅途里,第 1 千米的花费为 11,第 2 千米的花费为 12,第 3 千米的花费为 13,…,第 x 千米的花费为 x+10。
也就是说,如果一段旅途的总长度为 1 千米,则刚好需要花费 11,如果一段旅途的总长度为 2 千米,则第 1 千米花费 11,第 2 千米花费 12,一共需要花费 11+12=23。
J 大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入格式
输入的第一行包含一个整数 n,表示包括首都在内的 T 王国的城市数。
城市从 1 开始依次编号,1 号城市为首都。
接下来 n−1 行,描述 T 国的高速路(T 国的高速路一定是 n−1 条)。
每行三个整数 Pi,Qi,Di,表示城市 Pi 和城市 Qi 之间有一条双向高速路,长度为 Di 千米。
输出格式
输出一个整数,表示大臣 J 最多花费的路费是多少。
数据范围
1≤n≤105,
1≤Pi,Qi≤n,
1≤Di≤1000
输入样例:
5
1 2 2
1 3 1
2 4 5
2 5 4
输出样例:
135
分析:
由于题目说到不重复经过大城市,从首都到达每个大城市的方案都是唯一的。因此可以知道该图是一棵树,本题求的是树的直径
树的直径:树中长度最长的路径
1、任取一点x
2、找到距离x最远的点y
3、从y开始遍历,找到离y最远的点,与y最远的点的距离是树的直径
证明:y一定是树的直径的端点
假设y不是树的直径的端点,分两种情况,如图所示,其中uv是树的直径
情况1:xy与uv有交点,由于离x最远的点是y,因此
有 1 + 3 <= 3 + 4
即 3 <= 4
则 3 + 2 <= 4 + 2
由于 3 + 2是树的直径,因此4 + 2一定是树的直径,因此y不是树的直径的端点矛盾
情况2:xy与uv没有交点,由于离x最远的点是y,因此
有 1 + 2 >= 1 + 3 + 5
即 2 >= 3 + 5
即 2 > 5
则 2 + 3 > 5
则 2 + 3 + 5 > 4 + 5
由于 4 + 5是树的直径,但存在着一个长度更长的路径,因此y不是树的直径的端点矛盾
因此,y一定是树的直径的端点
dfs
1、通过深度优先遍历找到与x的最远距离的点y
2、再通过深度优先遍历找到与y的最远距离
注意:递归函数需要记录上一结点father
时间复杂度 O(n)
参考文献
小呆呆的题解(java)
#include
#define int long long
#define endl '\n'
#define x first
#define y second
using namespace std;
const int N = 1e5 + 10;
vector<pair<int, int>> h[N];
int dist[N];
void dfs(int u, int father, int distance)
{
dist[u] = distance;
for(auto node : h[u])
if(node.x != father)
dfs(node.x, u, distance + node.y);
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
for(int i = 0; i < n - 1; i ++)
{
int a, b, c;
cin >> a >> b >> c;
h[a].push_back({b, c});
h[b].push_back({a, c});
}
//找到任意点x找到距离最远的点y
dfs(1, -1, 0);
int u = 1;
for(int i = 1; i <= n; i ++)
{
if(dist[u] < dist[i])
u = i;
}
//找到离y最远的点的距离
dfs(u, -1, 0);
for(int i = 1; i <= n; i ++)
if(dist[u] < dist[i])
u = i;
int s = dist[u];
cout << 10 * s + s * (s + 1) / 2 << endl;
return 0;
}