[NOI2003][樹的直徑]逃學的小孩

題目

原題連接node

解說

分享題說實話最開始都沒什麼思路,以前的大部分基本都看了一下題解啓發思路。ios

但這道題我能夠大聲而驕傲地說:它  是  我  完  完  全  全  自  己  作  出  來  的  !ide

固然,代價就是Vjudge上WA了5遍,洛谷上WA了1遍,坑殺了我一節半課的時間。spa

那麼,轉到正題,思路是怎麼樣的呢?code

首先可見這個圖是一棵樹,咱們須要找到三個點,暫時叫ABC吧。其中(A到B的距離+C到AB距離中較短的)這一值最小。blog

(如下maxdis表明樹的直徑,maxv表明第一遍DFS找到的直徑端點,End表明第二遍DFS找到的另外一個端點,bj i表明點是否在直徑上,ans i 以及以後的ans1 i 表明節點 i 到maxv的距離,ans2 i 表明節點 i 到End的距離,b表明最後的答案)ci

很顯然這屬於樹的直徑題。用兩遍DFS找出樹的兩個頂點……以後呢?我在這裏第一次卡住了。get

因爲萬惡的樣例帶來的錯覺,我以爲題目要求的點必定是在直徑上。因此我就用了第三遍DFS,找出來了全部直徑上的點,在第二遍DFS的時候順帶計算出ans  i,以後循環一遍找到答案就行。循環大概就是:string

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

而後就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

 

幸甚至哉,歌以詠志。

相關文章
相關標籤/搜索