【例题&结论】【树(树的直径)】NKOJ 3694 电脑

来源:互联网 发布:java lucene 词干 编辑:程序博客网 时间:2024/06/05 04:58

NKOJ 3694 电脑
时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 时限1000ms

问题描述
给你一棵由n个节点构成的树,树中每条边都有一定的长度值。 对于树中的每个节点,请你找出树中离它最远的点,并输出它们的距离。

输入格式
第一行,一个整数n
接下来n-1行,每行三个整数a,b,c,表示点a和b之间有条长度为c的边

输出格式
n行,每行一个整数,第i行表示点i与其最远的点间的距离

样例输入
7
1 2 10
2 3 6
3 4 9
3 6 3
3 7 10
4 5 4

样例输出
29
19
16
25
29
19
26

提示
1<=n<=10000
1<=边长<=1000000000

来源 改编自hdu 2196

思路
/* (结论)树的直径:树中距离最远的两个点间的距离。
性质:
1、若树有多条直径,则这几条直径一定交叉。
2、树中各点的”最远点“一定为某直径的两端点之一。
求法:
任选一点,找出到该点距离最长的点s,从s出发,找出到s最远的点e,s到e的距离即为直径长度。*/

综上,各点到两端点距离dis1、dis2中最大的一个,即为所求。

代码:

#include<cstdio> #include<iostream> using namespace std; const int need=10004; #define ll long long  ll en[need*2],la[need*2],fi[need*2],le[need*2],ans[need]; bool visit[need]; ll m=0,s,an; void add(ll a,ll b,ll c) {     m++;     en[m]=b;     le[m]=c;     la[m]=fi[a];     fi[a]=m; } void dfs(ll k,ll v) {     if(visit[k]) return ;    visit[k]=true;     ans[k]=max(ans[k],v);     if(v>an)      {         an=v;         s=k;     }     ll t=fi[k],y,val;     while(t)     {         val=le[t],y=en[t];         if(!visit[y])        {               ll dis=v+val;             dfs(y,dis);         }         t=la[t];     } } int main() {     int n;scanf("%d",&n);     ll a,b,c;     for(ll i=1;i<n;i++)      {         scanf("%I64d%I64d%I64d",&a,&b,&c);         add(a,b,c),add(b,a,c);     }     an=0;     dfs(1,0);     int e=s;an=0;     for(int i=1;i<=n+n;i++) visit[i]=0;     dfs(e,0);     an=0;     for(int i=1;i<=n+n;i++) visit[i]=0;     dfs(s,0);     for(int i=1;i<=n;i++) printf("%I64d\n",ans[i]); } 
0 0
原创粉丝点击