树的直径——逃学的小孩(洛谷)
作者:互联网
先看题目:
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的父母会遵守以下两条规则:
- 如果A距离C比B距离C近,那么Chris的父母先去Shermie家寻找Chris,如果找不到,Chris的父母再去Yashiro家;反之亦然。
- 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
注意事项
标签:head,洛谷,小孩,ll,逃学,tot,maxn,Chris,include 来源: https://www.cnblogs.com/DZN2004/p/12662081.html