P4408 [NOI2003]逃学的小孩(树的直径)

题目描述

Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?一听说要考试,Chris的父母就心急如焚,他们决定在尽量短的时间内找到Chris。他们告诉Chris的老师:根据以往的经验,Chris现在必然躲在朋友ShermieYashiro家里偷玩《拳皇》游戏。现在,我们就从家出发去找Chris,一但找到,我们立刻给您打电话。说完砰的一声把电话挂了。

Chris居住的城市由N个居住点和若干条连接居住点的双向街道组成,经过街道x需花费Tx分钟。可以保证,任两个居住点间有且仅有一条通路。Chris家在点CShermieYashiro分别住在点A和点BChris的老师和Chris的父母都有城市地图,但Chris的父母知道点ABC的具体位置而Chris的老师不知。

为了尽快找到ChrisChris的父母会遵守以下两条规则:

  1. 如果A距离CB距离C近,那么Chris的父母先去Shermie家寻找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然。
  2. Chris的父母总沿着两点间唯一的通路行走。

显然,Chris的老师知道Chris的父母在寻找Chris的过程中会遵守以上两条规则,但由于他并不知道ABC的具体位置,所以现在他希望你告诉他,最坏情况下Chris的父母要耗费多长时间才能找到Chris

输入格式

输入文件第一行是两个整数N3 ≤ N ≤ 200000)和M,分别表示居住点总数和街道总数。

以下M行,每行给出一条街道的信息。第i+1行包含整数UiViTi1≤Ui, Vi ≤ N1 ≤ Ti ≤ 1000000000),表示街道i连接居住点UiVi,并且经过街道i需花费Ti分钟。街道信息不会重复给出。

输出格式

输出文件仅包含整数T,即最坏情况下Chris的父母需要花费T分钟才能找到Chris

输入输出样例

    输入

4 3

1 2 1

2 3 1

3 4 1

输出
4

思路分析:
  这道题要求我们求的是Chris的父母先后到两个朋友家的时间之和的最大值,我们令起点为A点,两个朋友家分别为B和C,那么很明显我们要的答案为
dis(B,C)+ min(dis(A,B),dis(A,C)),由于题目中说道任两个节点之间都有且只有一条道路,那么我们最终建的图就会是一个树的形状。我们当B,C

间距离最大时即当B,C为树的直径时可以取得最优,所以我们跑4遍DFS即可,第一遍任取一点求距离它最远的点,设为cnt1,第二遍从cnt1开始,求到cnt1距离最大的点

则此时cnt1-cnt2为树的直径。第三次,第四次分别从cnt1和cnt2出发,求出每个点到cnt1和cnt2的距离,最后从1到n扫一遍求出最优即可。

关于为什么B,C为直径时最优的贪心证明 大家可以看一下这里

网址:https://www.luogu.com.cn/blog/ILikeDuck/solution-p4408

附上代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=1e6+10;
 6 long long dis1[N],dis2[N];
 7 int n,m,cnt1,cnt2;
 8 struct Node{
 9     int next,to;
10     long long dis;
11 }edge[N];
12 int Head[N],tot;
13 void Add(int x,int y,long long z){
14     edge[++tot].to=y;
15     edge[tot].dis=z;
16     edge[tot].next=Head[x];
17     Head[x]=tot;
18 }
19 void dfs1(int u,int fa){  //四次DFS 
20     for(int i=Head[u];i;i=edge[i].next){
21         int v=edge[i].to;
22         if(v==fa) continue;
23         dis1[v]=dis1[u]+edge[i].dis;
24         if(dis1[v]>dis1[cnt1]) cnt1=v;
25         dfs1(v,u);
26     }
27 }
28 void dfs2(int u,int fa){
29     for(int i=Head[u];i;i=edge[i].next){
30         int v=edge[i].to;
31         if(v==fa) continue;
32         dis2[v]=dis2[u]+edge[i].dis;
33         if(dis2[v]>dis2[cnt2]) cnt2=v;
34         dfs2(v,u);
35     }
36 }
37 void dfs3(int u,int fa){
38     for(int i=Head[u];i;i=edge[i].next){
39         int v=edge[i].to;
40         if(v==fa) continue;
41         dis1[v]=dis1[u]+edge[i].dis;
42         dfs3(v,u);
43     }
44 }
45 void dfs4(int u,int fa){
46     for(int i=Head[u];i;i=edge[i].next){
47         int v=edge[i].to;
48         if(v==fa) continue;
49         dis2[v]=dis2[u]+edge[i].dis;
50         dfs4(v,u);
51     }
52 }
53 int main(){
54     scanf("%d%d",&n,&m);
55     for(int i=1;i<=m;++i){
56         int x,y,z;
57         scanf("%d%d%d",&x,&y,&z);
58         Add(x,y,z);Add(y,x,z);
59     }
60     dfs1(1,0);
61     dfs2(cnt1,0);
62     long long ans=dis2[cnt2];
63     memset(dis1,0,sizeof(dis1));
64     memset(dis2,0,sizeof(dis2));
65     dfs3(cnt1,0);dfs4(cnt2,0);
66     long long temp=0;
67     for(int i=1;i<=n;++i){   //比较那一个点作为A点好. 
68         long long d=min(dis1[i],dis2[i]);
69         if(d>temp) temp=d;
70     }
71     printf("%lld
",temp+ans);
72     return 0;
73 }
原文地址:https://www.cnblogs.com/li-jia-hao/p/12663739.html