樹網的核|圖論

題目描述 Description

  設T=(V, E, W) 是一個無圈且連通的無向圖(也稱爲無根樹),每條邊到有正整數的權,我們稱T爲樹網(treebetwork),其中V,E分別表示結點與邊的集合,W表示各邊長度的集合,並設T有n個結

點。

  路徑:樹網中任何兩結點a,b都存在唯一的一條簡單路徑,用d(a, b)表示以a, b爲端點的路徑的長度,它是該路徑上各邊長度之和。我們稱d(a, b)爲a, b兩結點間的距離。

  D(v, P)=min{d(v, u), u爲路徑P上的結點}。

  樹網的直徑:樹網中最長的路徑成爲樹網的直徑。對於給定的樹網T,直徑不一定是唯一的,但可以證明:各直徑的中點(不一定恰好是某個結點,可能在某條邊的內部)是唯一的,我們稱該點爲樹

網的中心。

  偏心距ECC(F):樹網T中距路徑F最遠的結點到路徑F的距離,即ECC(F)=max{d(v, F),v∈V}

  任務:對於給定的樹網T=(V, E, W)和非負整數s,求一個路徑F,他是某直徑上的一段路徑(該路徑兩端均爲樹網中的結點),其長度不超過s(可以等於s),使偏心距ECC(F)最小。我們稱這個路徑

爲樹網T=(V, E, W)的核(Core)。必要時,F可以退化爲某個結點。一般來說,在上述定義下,核不一定只有一個,但最小偏心距是唯一的。

  下面的圖給出了樹網的一個實例。圖中,A-B與A-C是兩條直徑,長度均爲20。點W是樹網的中心,EF邊的長度爲5。如果指定s=11,則樹網的核爲路徑DEFG(也可以取爲路徑DEF),偏心距爲8。如果

指定s=0(或s=1、s=2),則樹網的核爲結點F,偏心距爲12。

 

輸入輸出格式 Input/output

輸入格式:

輸入文件core.in包含n行:

第1行,兩個正整數n和s,中間用一個空格隔開。其中n爲樹網結點的個數,s爲樹網的核的長度的上界。設結點編號以此爲1,2,……,n。

從第2行到第n行,每行給出3個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和長度。例如,“2 4 7”表示連接結點2與4的邊的長度爲7。

所給的數據都是爭取的,不必檢驗。

 

輸出格式:

輸出文件core.out只有一個非負整數,爲指定意義下的最小偏心距。

 

輸入樣例1】

5 2

1 2 5

2 3 2

2 4 4

2 5 3

【輸入樣例2】

8 6

1 3 2

2 3 2 

3 4 6

4 5 3

4 6 4

4 7 2

7 8 3

 

【輸出樣例1】

5

【輸出樣例2】

5

 

40%的數據滿足:5<=n<=15

70%的數據滿足:5<=n<=80

100%的數據滿足:5<=n<=300,0<=s<=1000。邊長度爲不超過1000的正整數

NOIP 2007 提高第四題

 

題目分析:先進行題目中定義的整理。

    路徑:d(a, b)表示以a, b爲端點的路徑的長度,它是該路徑上各邊長度之和。我們稱d(a, b)爲a, b兩結

點間的距離。

    樹網的直徑:樹網中最長的路徑成爲樹網的直徑。對於給定的樹網T,直徑不一定是唯一的,但可以證明:

    各直徑的中點(不一定恰好是某個結點,可能在某條邊的內部)是唯一的,我們稱該點爲樹網的中心。 證明:設A爲路徑1的中點。枚舉得到路徑2。設路徑2的中點爲B。若A<>B,則因爲圖是無環連

通的,所以必有路徑1大於或小於路徑2。得證。

    偏心距ECC(F):樹網T中距路徑F最遠的結點到路徑F的距離,即ECC(F)=max{d(v, F),v∈V}

 

解析:因爲點的個數不超過300,我們可以用Floyd直接計算兩點間的最短路徑。顯然我們只需要一條直徑。求直徑的方法是選擇節點1,找到離它最遠的一個節點i,接着再求離i最遠的節點j。d(i,j)即

爲直徑(利用直徑的最大性可證)

    接着枚舉直徑中的邊。顯然如果d(i,k)+d(k,j)=d(i,j)那麼k是直徑中的點。接着枚舉與k相連的點q作爲終點。顯然,路徑外最遠的一點必然是直徑的端點(否則直徑不爲最長)。計算路徑起止點到

離其較近端點的距離。最後輸出最小的偏心距即可。

 

代碼如下(C++崩潰了,只好用Pascal寫):

var i,j,k,n,s,a,b,c,st,ed,maxnow,ans,q:longint;

  map:array[1..300,1..300]of longint;

 

function max(a,b:longint):longint;

begin

  if a>b then exit(a);

  exit(b);

end;

 

function min(a,b:longint):longint;

begin

  if a<b then exit(a);

  exit(b);

end;

 

begin

 readln(n,s);

 for i:=1 to n do

   for j:=1 to n do

     if (i<>j) then map[i,j]:=1111117;

 

 for i:=1 to n-1 do

   begin readln(a,b,c); map[a,b]:=c; map[b,a]:=c;  end;

 

 for k:=1 to n do

   for i:=1 to n do

     for j:=1 to n do

       if ( (map[i,k]+map[k,j])<map[i,j] ) then

         begin

           map[i,j]:=map[i,k]+map[k,j];

           map[j,i]:=map[i,j];

         end;

 

 maxnow:=0; st:=0; ed:=0;

 for i:=2 to n do if (map[i,j]<>1111117)and(map[1,i]>maxnow) then

   begin

     maxnow:=map[1,i]; st:=i;

   end;

 maxnow:=0;

 for i:=1 to n do if (map[i][st]<>1111117)and(map[i,st] >maxnow) then

   begin maxnow:=map[i][st]; ed:=i; end;

 

 ans:=1111117;

 for k:=1 to n do

   for q:=1 to n do

     if (map[k,q]<=s) then

       if (max(min(map[st][k],map[st][q]),min(map[k][ed],map[q][ed]))<ans) then

         ans:=max(min(map[st][k],map[st][q]), min(map[k][ed],map[q][ed]));

 

 writeln(ans);

end.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章