NOIP2007 樹網的核

2021-05-26 21:28:11 字數 1805 閱讀 2175

參考了某位神牛的題解之後才發現原來這道題並不是很難……還是自己太弱了

原來的想法本來是快排找直徑,通過dfs確定在直徑中的點,然後再分別列舉每兩個點形成的邊,以邊的兩點做floyd通過打擂台確定偏心距。

自己的想法真的很麻煩而且就算編出來少說也要200+行的**,這在比賽中是不可能也是做不到的。

正規且高效的解法是:

1:通過floyd求每兩個點之間距離,通過打擂台不斷更新確定出直徑。

2:通過列舉起點和終點找出兩點之間距離與直徑相等的兩個點,再對全域性再一次列舉,此次列舉為在直徑中的路徑,完全不需要dfs,直接判斷就可以實現,即起點到列舉點的距離+列舉點到終點的距離=直徑,則這個點∈直徑。

3:列舉完第乙個點後繼續列舉第二個點,這次不僅要滿足第乙個點要滿足的條件,同時第乙個點與第二個點之間的距離必須要≤s。

4:通過數學證明可以發現,某直徑上的偏心距一定還在直徑上(因為偏心距是最遠距離,如果偏心距不在直徑上,說明這就不是一條直徑)。因此不需要再次列舉,只需要在路徑到直徑兩個端點的距離中找最小值的最大值即可(注意點的同時性)。

program core;

var n,s:longint;

d:array [0..300,0..300] of longint;

procedure init;

var i,j,x,y,dis:longint;

begin

readln(n,s);

for i:=1 to n do for j:=1 to n do d[i,j]:=maxint;

for i:=1 to n-1 do

begin

readln(x,y,dis);

d[y,x]:=dis;

d[x,y]:=dis;

end;

end;

function max(x,y:longint):longint;

begin

if x>y then exit(x) else exit(y);

end;

function min(x,y:longint):longint;

begin

if xi) and (k<>j) and (i<>j) then

begin

if d[i,j]>d[i,k]+d[k,j] then d[i,j]:=d[i,k]+d[k,j];

end;

end;

end;

end;

for i:=1 to n do for j:=1 to n do if (d[i,j]>trip) and (d[i,j]<>maxint) then trip:=d[i,j];

for i:=1 to n do for j:=1 to n do if d[i,j]=maxint then begin d[i,j]:=0; d[j,i]:=0; end;

for i:=1 to n-1 do

begin

for j:=i+1 to n do

begin

if d[i,j]=trip then

begin

for k:=1 to n do

begin

if d[i,k]+d[k,j]=trip then

begin

for l:=1 to n do

begin

if (d[i,l]+d[l,j]=trip) and (d[k,l]<=s) then

begin

ecc:=max(min(d[k,i],d[l,i]),min(d[k,j],d[l,j]));

if ecc

NOIp 2007 樹網的核

問題描述 設 t v,e,w 是乙個無圈且連通的無向圖 也稱為無根樹 每條邊帶有正整數的權,我 們稱t 為樹網 treenetwork 其中v,e分別表示結點與邊的集合,w 表示各邊長度的集合,並設t 有n個結點。路徑 樹網中任何兩結點a,b 都存在唯一的一條簡單路徑,用d a,b 表示以a,b 為...

noip2007 樹網的核

樹網的核 題目描述 設t v,e,w 是乙個無圈且連通的無向圖 也稱為無根樹 每條邊到有正整數的權,我們稱t為樹網 treebetwork 其中v,e分別表示結點與邊的集合,w表示各邊長度的集合,並設t有n個結點。路徑 樹網中任何兩結點a,b都存在唯一的一條簡單路徑,用d a,b 表示以a,b為端點...

noip2007 樹網的核

問題描述 設t v,e,w 是乙個無圈且連通的無向圖 也稱為無根樹 每條邊帶有正整數的權,我們稱t為樹網 treenetwork 其中v,e分別表示結點與邊的集合,w表示各邊長度的集合,並設t有n個結點。路徑 樹網中任何兩結點a,b都存在唯一的一條簡單路徑,用d a,b 表示以a,b為端點的路徑的長...