树的直径——逃学的小孩(洛谷)

先看题目:

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

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

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

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

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

题意很好理解。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

怎么做?

我觉得是个人的话都能想到树的直径。

重点是怎么用?

化简题目:一句话题意:在一棵树上找三个点A、B、C使得AB+AC的值最大(满足AC<=BC)

这样是不是就知道如何做了。

AB的最大值很好想,显然就是树的直径,在一棵树中没有比直径更长的路程了

那么AC的最大值呢,我们可以在dfs求树的直径的时候顺便把每一个点到A、B的价值都求出来,在这两个价值中取较小值(因为要先到比较近的点)

最后再枚举一遍求最优决策(最大值),这实际上是一种贪心的思想

证明的话可以去洛谷上看。

下面是代码,紧缩板 ,可能不好理解。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=500010;
 8 typedef long long ll;
 9 struct node{
10     ll from,to,next,value;
11 }b[maxn];
12 ll n,m,head[maxn],tot=1;
13 void add(ll xx,ll yy,ll zz){
14     b[tot].from=xx;b[tot].to=yy;b[tot].next=head[xx];b[tot].value=zz;head[xx]=tot++;
15 }
16 ll dis[maxn],disa[maxn],disb[maxn],A,B;
17 ll mostlong,JL=-0x3f3f3f3f3f3f3f3f,ID=0;
18 void DFS(ll now,ll fa){
19     for(ll i=head[now];i!=-1;i=b[i].next){
20         ll u=b[i].to;ll da=b[i].value;
21         if(u==fa) continue;
22         dis[u]=dis[now]+da;
23         if(dis[u]>JL){
24             JL=dis[u];ID=u;
25         }
26         DFS(u,now);
27     }
28 }
29 int main(){
30     //freopen("a.in","r",stdin);
31     scanf("%lld%lld",&n,&m);
32     memset(head,-1,sizeof(head));
33     for(ll i=1;i<=m;i++){
34         ll xx,yy,zz;
35         scanf("%lld%lld%lld",&xx,&yy,&zz);
36         add(xx,yy,zz);add(yy,xx,zz);
37     }DFS(1,0);A=ID;
38     memset(dis,0,sizeof(dis));
39     ID=0,JL=-0x3f3f3f3f3f3f3f3f;
40     DFS(A,0);B=ID,mostlong=JL;
41     ID=0,JL=-0x3f3f3f3f3f3f3f3f;
42     for(ll i=1;i<=n;i++)disa[i]=dis[i];
43     memset(dis,0,sizeof(dis));DFS(B,0);
44     for(ll i=1;i<=n;i++)disb[i]=dis[i];
45     ll ans=-0x3f3f3f3f3f3f3f3f;
46     for(ll i=1;i<=n;i++)ans=max(ans,min(disa[i],disb[i]));
47     printf("%lld\n",ans+mostlong);
48     return 0;
49 }
写的有点烂

总结的话,其实就是道板子题,超水。

但是注意一下力争满分。

1、开long long,并且赋值为无穷大时要写8个3f:0x3f3f3f3f3f3f3f3f

2、双向边,开数组时一定要乘2

注意事项

猜你喜欢

转载自www.cnblogs.com/DZN2004/p/12662081.html