P4408 [NOI2003]逃学的小孩

Link

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;
}
posted @ 2020-10-25 06:26  genshy  阅读(65)  评论(0编辑  收藏  举报