P4408 [NOI2003]逃学的小孩
desprition
给你一颗树,让你找出三个点, \(A,B,C\) 满足 \(AB \leq AC\) 使得 \(AB + BC\) 的长度最大。
并输出这个长度
sloution
树的直径加暴力枚举。
首先,要是 \(BC\) 的距离最大,我们肯定要选树的直径,然后就确定了 \(B,C\) 是树的直径的两个端点,
现在主要是怎么确定 \(A\) ,我们在求树的直径的时候,可以求出每个点到 \(B,C\) 这两点之间的距离 ,跑三遍 \(bfs\) 就行。
之后再暴力枚举一下 \(A\) ,最后的答案就是 \(max(直径 + min(d1[i],d2[i]))\)
然后就做完了。具体证明的话不太会emmmm.
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define int long long
const int N = 1e5+10;
int n,m,tot,zhijing,ans,u,v,w,st,en;
int head[N],d1[N],d2[N];
struct node
{
int to,net,w;
}e[N<<1];
inline int read()
{
int s = 0,w = 1; char ch= getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
void add(int x,int y,int w)
{
e[++tot].to = y;
e[tot].w = w;
e[tot].net = head[x];
head[x] = tot;
}
void bfs(int x)
{
for(int i = 1; i <= n; i++) d1[i] = -1;
queue<int> q;
q.push(x); d1[x] = 0;
while(!q.empty())
{
int t = q.front(); q.pop();
for(int i = head[t]; i; i = e[i].net)
{
int to = e[i].to;
if(d1[to] == -1)
{
d1[to] = d1[t] + e[i].w;
q.push(to);
}
}
}
}
void bfs2(int x)
{
for(int i = 1; i <= n; i++) d2[i] = -1;
queue<int> q;
q.push(x); d2[x] = 0;
while(!q.empty())
{
int t = q.front(); q.pop();
for(int i = head[t]; i; i = e[i].net)
{
int to = e[i].to;
if(d2[to] == -1)
{
d2[to] = d2[t] + e[i].w;
q.push(to);
}
}
}
}
signed main()
{
n = read(); m = read();
for(int i = 1; i <= n-1; i++)
{
u = read(); v = read(); w = read();
add(u,v,w); add(v,u,w);
}
bfs(1);
for(int i = 1; i <= n; i++)
{
if(d1[i] > d1[st]) st = i;
}
bfs(st);
for(int i = 1; i <= n; i++)
{
if(d1[i] > d1[en]) en = i;
}
zhijing = d1[en];
bfs2(en);
for(int i = 1; i <= n; i++)
{
ans = max(ans,min(d1[i],d2[i]));
}
printf("%lld\n",zhijing+ans);
return 0;
}