Description
有n个点,由m条边连接,第i条边的边权是wi。这些点和边构成了一棵树.
对于树来说,我们都知道其最远的两个点之间的距离称为直径
现在树上每个节点上都有一个人,他必须先跑到离他较近的直径的某个端点,再跑到直径的另一个端点
现在问你,这N个人跑得最远的人,要跑多远的路
Format
Input
第一行给出n,m
接下来m行描述边,边权<=1000000000
N<=2e5
Output
如题
Samples
输入数据 1
4 3
1 2 1
2 3 1
3 4 1
输出数据 1
4
题解
思路
树的直径的定义:树上任意两节点之间最长的简单路径即为树的直径。
我们发现这道题可以先求出树的直径和那两个结点,再求出每个点到这两个结点的距离。然后便利每个点,用这个点到那两个结点的距离取最小值再加上树的直径再取最大值输出就行了。(具体看注释吧~~,包括树的直径的求法)
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node //结构体
{
int ans,len;
};
int n,m,x,y,z,maxx,t,a[1000001],b[1000001];
bool cmp=1;
vector<node> adj[1000001];
void dfs(int u,int fa,int dep) //求树的直径
{
if(maxx<dep) //只要此时的深度比最大深度还要大,就更新最大深度
{
maxx=dep;
t=u;
}
for(int i=0;i<adj[u].size();i++)
{
node t9=adj[u][i];
if(t9.ans==fa)
{
continue;
}
dfs(t9.ans,u,dep+t9.len);
}
}
void dfs1(int s,int d,int dep) //求出每个结点与树的直径的第一个结点的距离并存储在a数组里
{
a[s]=dep;
for(int i=0;i<adj[s].size();i++)
{
node t9=adj[s][i];
if(t9.ans!=d)dfs1(t9.ans,s,dep+t9.len);
}
}
void dfs2(int s,int d,int dep) //求出每个结点与树的直径的第二个结点的距离并存储在b数组里
{
b[s]=dep;
for(int i=0;i<adj[s].size();i++)
{
node t9=adj[s][i];
if(t9.ans!=d)dfs2(t9.ans,s,dep+t9.len);
}
}
signed main()
{
cin>>n>>m; //输入
for(int i=1;i<=m;i++)
{
cin>>x>>y>>z;
adj[x].push_back({y,z}); //双向建边
adj[y].push_back({x,z});
}
dfs(1,0,0); //先求出离1这个根节点最远的叶子结点
int c1=t; //存储树的直径的第一个结点
maxx=0;
dfs(t,0,0); //再求出离以树的直径的第一个结点为根结点的最远的第二个结点和树的直径maxx,此时的t就是树的直径的第二个结点
dfs1(c1,0,0);
dfs2(t,0,0);
int t1=0;
for(int i=1;i<=n;i++)
{
t1=max(min(a[i],b[i])+maxx,t1); //用每个点到那两个结点的距离取最小值再加上树的直径再取最大值
}
cout<<t1; //输出
return 0;
}
如果觉得写得好的话就点个赞吧!
推荐树的直径定义及做法链接:https://blog.csdn.net/weq2011/article/details/128554959?spm=1001.2014.3001.5502