傳送門
這道題的題意首先要讀懂。
簡單說,題目是想要我們選取乙個樹核,使得樹核外的其他點到樹核的距離的最大值最小。
我們存圖採用鄰接矩陣和鍊錶兼用法,鄰接矩陣用於跑floyd,鍊錶用於遍歷與某個點直接相連的點。
我們首先用floyd處理出各個點之間的距離,備用。
接下來我們先找出直徑的長度,這個很好解決,直接列舉每兩個點之間的距離,最大的乙個就是。
題目說我們的樹核一定是在直徑上,所以我們應該找出直徑再進行下一步。
這個應該比較容易,我們先列舉找出直徑的端點,然後dfs一下即可。
但是請注意,我們只需要乙個直徑即可,不需要每個直徑都進行一邊找樹核
這個我單獨放在後面證明。
所以我們找到乙個直徑後就可以break掉了。
那麼當我們把直徑存在陣列裡以後,接下來就是找樹核了。
怎麼辦?列舉好了。
那麼應該按什麼順序去列舉呢?
因為我們的直徑一定是一條鏈(這個應該不要證明),而樹核一定是連續的,所以我們可以用直徑陣列的下表來表示,即l和r。
我們此處還要用到乙個結論:
乙個樹核一定不會比它的子樹核更差,即乙個樹核的偏心距一定小於等於其子樹核的偏心距
這個我們也放到後面證明。
所以這提示我們,我們列舉樹核時,計算過乙個樹核後一定不能計算它的子樹核(即被其包含的樹核)。所以我們的移動策略就出來了:
如果我們加入樹核右邊的乙個新點時,樹核長度小於等於s,那麼r++
如果不行,那麼我們就丟棄左邊的點,即l++,直到可以囊括右邊的新點,那麼r++
如果減到只剩乙個點時,仍然不能囊括新的點,說明這條邊的長度大於s,那麼我們就直接加入新的點,把舊點全部丟掉,即l++,r++
這樣就可以了。我們可以發現按此順序執行後r一定會增加的,也就是說變換後的樹核一定會加入乙個新的點,也就絕對和原來的樹核不一樣,而同時又保證了,直徑上每個點都有機會加入樹核,所以就成功地列舉完了所有的樹核。
那麼既然已經可以列舉樹核了,接下來就是計算每乙個樹核的偏心距了。
題目說是樹核外每乙個點到樹核距離的最大值,我們可以轉換一下,從樹核上各個點到其他點的距離的最大值。
但是這樣的說法是有問題的,還有乙個要求,即樹核上的某個點到樹核外這個點的路徑不能和樹核有重疊,那麼怎麼保證這一點呢?
這就要用到我們的鍊錶了。
我們先列舉樹核上的點,對於每個點(設為cur),我們列舉與其相連的點,然後找出非樹核內部的點,設為u,然後再列舉所有的點(設為k),滿足如下的式子即可說明k與cur的路徑不與樹核重疊:
[u][k]
[k];
應該很顯然,如果需要證明,我放在後面。
這樣問題就迎刃而解了。
下面我們來證明一下前面說的幾個結論:
直徑不一定是唯一的,但可以證明:各直徑的中點(不一定恰好是某個結點,可能在某條邊的內部)是唯一的,我們稱該點為樹網的中心。那麼我們現在分情況討論。
首先,中心在節點。
如圖,數字只是邊的標號,不是長度。長度可以由圖直接看出。而且,這裡只畫出了最兩端的端點,也就是說我連線的線上還有其他的點未標出,如1、2、3的交點。
這裡有六條直徑,分別是134、135、136、45、46、56
紅點是中心。
那麼我們來看其他支鏈與直徑的關係,我們可以很容易地知道,中心上的其他支鏈,對於每條直徑都是等價的,所以不必考慮每一條直徑。
再看直徑上其他結點的小支鏈,如2
若2的長度大於1,那麼直徑就不再是135,違背假設,所以2的長度小於等於1.
對於與2相交的直徑,如135,其上的任意一點到2的端點的距離,均小於到4或6的端點,因此並不影響偏心距(因為偏心距是最大值)。
對於與2不相交的直徑,如46,那麼就更顯然了,其上每一點到2端點的距離均小於到1端點的距離,同樣不影響。
而對於直徑本身的支鏈,由對稱性可知影響是一樣的。
綜上,所有的直徑對於本圖是等價的。
那麼對於中心在邊上的也是類似的證明思路,自己證明試試看吧!
我們直接上圖:
這裡我們取123作為樹核,那麼其子樹核之一為23。
對於未變動的2和3,其連線的4,5,7到其的距離均未變。
而對與1這一邊,我們加上乙個1後,6到樹核的距離變短了。
也就是說樹核長度增加後,其他點到樹核的距離,要麼沒變,要麼減小了,可見偏心距也是要麼沒變,要麼減小。
所以乙個樹核一定不會比子樹核差。
挺拗口的,反正你也知道我要證明前面哪句話。
這是較為明顯的。
若該路徑與樹核還有另一交點v,即cur和v之間有兩條不同路徑,一條是我們選取的路徑,另一條是通過樹核的路徑(一定是不同的,只要注意兩條路徑與cur的連線點即可),那麼我們就形成了乙個環,然而這是乙個樹,違背題意。
所以,最後就形成了我們的**:
#include
#include
#include
#include
using
namespace std;
const
int maxn=
305;
vector<
int> g[maxn]
;//鍊錶
int n,s;
[maxn]
;//鄰接矩陣
int dm[maxn]
;//儲存直徑路徑
int vis[maxn]
;//是否存在於當前選定的和核
int dia;
//直徑長度
int ans;
//最終答案
int num;
//直徑所含節點數
intcalc
(int l,
int r)
for(
int k=
1;k<=n;k++)}
}}return curans;
}void
dfs(
int cur,
int tar)
for(
int i=
0;i.size()
;i++)}
}void
work
(int u,
int v)
else}if
(l==r)
} ans=
min(ans,
calc
(l,r));
}}intmain()
for(
int k=
1;k<=n;k++)}
}}ans=
0x3f3f3f3f
; dia=0;
for(
int i=
1;i<=n;i++)}
}for
(int i=
1;i<=n;i++)}
}printf
("%d"
,ans)
;return0;
}
NOIP2007提高組 樹網的核
noip2007提高組試題4。設 t v,e,w 是乙個無圈且連通的無向圖 也稱無根樹 每條邊帶有正整數的權,我們稱 t 為樹網 treenetwork 其中 v,e 分別表示結點與邊的集合,w 表示各邊長度的集合,並設 t 有 n 個結點。路徑 樹網中任何兩個結點 a,b 都存在唯一的一條簡單路徑...
NOIP2007 樹網的核
參考了某位神牛的題解之後才發現原來這道題並不是很難 還是自己太弱了 原來的想法本來是快排找直徑,通過dfs確定在直徑中的點,然後再分別列舉每兩個點形成的邊,以邊的兩點做floyd通過打擂台確定偏心距。自己的想法真的很麻煩而且就算編出來少說也要200 行的 這在比賽中是不可能也是做不到的。正規且高效的...
NOIp 2007 樹網的核
問題描述 設 t v,e,w 是乙個無圈且連通的無向圖 也稱為無根樹 每條邊帶有正整數的權,我 們稱t 為樹網 treenetwork 其中v,e分別表示結點與邊的集合,w 表示各邊長度的集合,並設t 有n個結點。路徑 樹網中任何兩結點a,b 都存在唯一的一條簡單路徑,用d a,b 表示以a,b 為...