BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011
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:
輸入文件core.in包含n行:
第1行,兩個正整數n和s,中間用一個空格隔開。其中n為樹網結點的個數,s為樹網的核的長度的上界。設結點編號以此為1,2,……,n。
從第2行到第n行,每行給出3個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和長度。例如,“2 4 7”表示連接結點2與4的邊的長度為7。
Output:
輸出文件core.out只有一個非負整數,為指定意義下的最小偏心距。
思路:
找到最長鏈後暴力枚舉可以過掉NOIP的測試數據,但這個算法太鹹魚了 我們顯然不能這麽鹹魚下去對不對?
考慮貪心,找到直徑後枚舉一個起點,然後終點明顯越遠越好可以直接確定,然後從每個節點出發求偏心距,復雜度N2
也可以對偏心距進行二分枚舉答案然後求直徑上的核,復雜度NlogN
但復雜度可以到On
預處理出從直徑上的每個節點出發,能到達最遠點的距離d,並用前綴和預處理出直徑上兩兩點間的距離
那麽拿一個長度為s的滑動窗口掃一遍直徑求出最小值就行了
沒了
#include<bits/stdc++.h> using namespace std; const int N = 300010; int head[N], now = 1; struct edges{ int to, next, w; }edge[N<<1]; void add(int u, int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;} int n, lim, dep[N], d[N], pre[N], pos1, pos2; bool isd[N]; int mymax(int x,int y,int z){ return max(x, y) > z ? max(x, y):z; } void dfs1(int x,int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; dep[v] = dep[x] + edge[i].w; dfs1(v, x); } if(dep[x] > dep[pos1]) pos1 = x; } void dfs2(int x,int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; d[v] = d[x] + edge[i].w; pre[v] = i; dfs2(v, x); } if(d[x] > d[pos2]) pos2 = x; } int dis[N]; void dfs(int x, int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa || isd[v]) continue; dfs(v, x); dis[x] = max(dis[x], dis[v] + edge[i].w); } } int a[N], tot; int main(){ scanf("%d%d",&n, &lim); int x, y, z; for(int i = 1; i < n; i++){ scanf("%d%d%d",&x, &y, &z); add(x, y, z); add(y, x, z); } dfs1(1, -1); dfs2(pos1, -1); // cout<<pos1<<" "<<pos2<<endl; for(int i = pos2; i; i = edge[pre[i] ^ 1].to) isd[i] = 1 ,a[++tot] = i; int ans = 1e9, mx = 0; for(int i = 1; i <= tot; i++){ dfs(a[i], -1); mx = max(mx, dis[a[i]]); } int i = 1; for(int j = i; j <= tot; j++){ while(d[a[i]] - d[a[j]] > lim) i++; int tmp = mymax(mx, d[a[1]] - d[a[i]], d[a[j]] - d[a[tot]]); ans = min(ans, tmp); } printf("%d\n",ans); return 0; }View Code
BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011