【洛谷 P4408】逃学的小孩【树的直径】

67 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述


知识点树的直径


解题思路

题目中“可以保证,任两个居住点间有且仅有一条通路”说明输入数据是一棵树。显然最优解需要从C先跑到A在跑到B.或者从C先跑到B在跑到A。

假设我们已经确定A,B点,那么AB是必走的,CA,CB会选取其中小的一段走,所以我们的C点要满足min(CA,CB)最大,这样就可以使答案最大。

如何确定A,B点?既然AB是必走的,那当然越长越好,所以就是树的直径了。由于这里只需要求树直径的端点和总长而不用求具体路线,我就选择了DFS来求。

简要介绍一下DFS求直径的方法:随意选取一个点,DFS出离它距离最大的点(设为P),再以P为起点,DFS出离它距离最大的点(设为Q),P,Q两点就是我们的A和B。

记得开long long


代码

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;

int n,m,u,v,t,k=1,s,e,w,head[400010];
ll maxn,ans,fs[400010],fe[400010],f[400010],d[400010];

struct c {
	int x,next;
	ll w;
} a[400010];

void add(int x,int y,ll w) {
	a[k].x=y;
	a[k].next=head[x];
	a[k].w=w;
	head[x]=k;
	k++;
}

void dfs(int x,int fa) {
	if(maxn<d[x]) {
		maxn=d[x];
		w=x;
	}
	for(int i=head[x]; i; i=a[i].next) {
		int y=a[i].x;
		if(y!=fa) {
			d[y]=d[x]+a[i].w;
			dfs(y,x);
		}
	}
}

void dfs2(int x,int fa) {
	for(int i=head[x]; i; i=a[i].next) {
		int y=a[i].x;
		if(y!=fa) {
			f[y]=f[x]+a[i].w;
			dfs2(y,x);
		}
	}
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=m; i++) {
		scanf("%d%d%lld",&u,&v,&t);
		add(u,v,t);
		add(v,u,t);
	}
	dfs(1,0);
	s=w;
	d[s]=0,maxn=0;
	dfs(s,0);
	e=w;
	dfs2(s,0);
	for(int i=1; i<=n; i++)
		fs[i]=f[i];
	f[e]=0;
	dfs2(e,0);
	for(int i=1; i<=n; i++)
		fe[i]=f[i];
	for(int i=1; i<=n; i++) {
		if(i!=s&&i!=e)
			ans=max(ans,min(fe[i],fs[i]));
	}

	printf("%lld",ans+maxn);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值