[NOI2003][树的直径]逃学的小孩

题目

原题链接

解说

分享题说实话最开始都没什么思路,之前的大部分基本都看了一下题解启发思路。

但这道题我可以大声而骄傲地说:它  是  我  完  完  全  全  自  己  做  出  来  的  !

当然,代价就是Vjudge上WA了5遍,洛谷上WA了1遍,坑杀了我一节半课的时间。

那么,转到正题,思路是怎么样的呢?

首先可见这个图是一棵树,我们需要找到三个点,暂时叫ABC吧。其中(A到B的距离+C到AB距离中较短的)这一值最小。

(以下maxdis代表树的直径,maxv代表第一遍DFS找到的直径端点,End代表第二遍DFS找到的另一个端点,bj i代表点是否在直径上,ans i 以及之后的ans1 i 代表节点 i 到maxv的距离,ans2 i 代表节点 i 到End的距离,b代表最后的答案)

很显然这属于树的直径题。用两遍DFS找出树的两个顶点……之后呢?我在这里第一次卡住了。

由于万恶的样例带来的错觉,我觉得题目要求的点一定是在直径上。所以我就用了第三遍DFS,找出来了所有直径上的点,在第二遍DFS的时候顺带计算出ans  i,之后循环一遍找到答案就行。循环大概就是:

 for(int i=1;i<=n;i++) if(bj[i]==1&&i!=End&&i!=maxv) b=max(b,min(maxdis-ans[i],ans[i]));  

然后就WA了。

之后很长时间我就卡在了这个代码的框框里,因为我一直坚定地认为要求的点在直径上。卡了半天还是感谢洛谷提供的一组错误样例让我恍然大悟:

我的C为什么一定要在直径上?!

下面是洛谷给的样例:

简洁明了但很有说服力。

显然,树的直径是2-4或3-4。由于这两种没有差别下面就用2-4举例。

如果按照之前的想法,C在直径上,那么我算出来的结果是4.但若我们选3作为C呢?

2到4的距离+3到2,4距离中较短的=5。

也就是说C不一定在直径上。

噫,好了,全崩了。

但是思路正确了应该就没什么问题了。我们在第二遍dfs的时候顺带算出各点到maxv的距离,之后再DFS一遍算出各点到End的距离,之后把各个点遍历一遍算min(ans1[i],ans2[i])+maxdis的最大值即可。

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<queue>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cmath>
 7 using namespace std;
 8 typedef long long ll;
 9 const int maxn=200000+3;
10 int n,m,tot,head[maxn],End,maxv;
11 ll maxdis,ans1[maxn],ans2[maxn];
12 struct node{
13     int to,next;
14     ll w;
15 }e[2*maxn];
16 void Add(int from,int to,ll w){
17     e[tot].w=w;
18     e[tot].to=to;
19     e[tot].next=head[from];
20     head[from]=tot;
21     tot++;
22 }
23 void dfs1(int u,int f,ll dis){//找第一个端点 
24     if(maxdis<dis) {
25         maxv=u;
26         maxdis=dis;
27     }
28     for(int i=head[u];i;i=e[i].next){
29         int v=e[i].to;ll w=e[i].w;
30         if(v==f) continue;
31         dfs1(v,u,dis+w);
32     }
33 }
34 void dfs2(int u,int f,ll dis){//找第二个端点 
35     ans1[u]=dis;//顺带求出所有点到maxv的距离 
36     if(maxdis<dis) {
37         maxdis=dis;
38         End=u;
39     }
40     for(int i=head[u];i;i=e[i].next){
41         int v=e[i].to;ll w=e[i].w;
42         if(v==f) continue;
43         dfs2(v,u,dis+w);
44     }
45 }
46 void dfs3(int u,int f,ll dis){//求所有点到End的距离 
47     ans2[u]=dis;
48     for(int i=head[u];i;i=e[i].next){
49         int v=e[i].to;ll w=e[i].w;
50         if(v==f) continue;
51         dfs3(v,u,dis+w);
52     }
53 }
54 int main(){
55     int n,m;
56     tot=1;
57     cin>>n>>m;
58     for(int i=1;i<=m;i++){
59         int from,to;ll w;
60         cin>>from>>to>>w;
61         Add(from,to,w);
62         Add(to,from,w);
63     }
64     dfs1(1,-1,0);
65     maxdis=0;
66     dfs2(maxv,-1,0);
67     dfs3(End,-1,0);
68     ll b=-1;
69     for(int i=1;i<=n;i++) if(i!=End&&i!=maxv) b=max(b,min(ans1[i],ans2[i])+maxdis); 
70     //找最佳点 
71     cout<<b;
72     return 0;
73 }
View Code

 

幸甚至哉,歌以咏志。

posted @ 2020-04-08 22:10  DarthVictor  阅读(155)  评论(0编辑  收藏  举报
莫挨老子!