1. 程式人生 > >NOIP2007 樹網的核 [dfs] [資料結構] [樹的直徑]

NOIP2007 樹網的核 [dfs] [資料結構] [樹的直徑]

樹網的核
(core.pas/c/cpp)
【問題描述】
設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的距離,即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。

【輸入】
輸入檔案core.in包含n行:
第1行,兩個正整數n和s,中間用一個空格隔開。其中n為樹網結點的個數,s為樹網的核的長度的上界。設結點編號以此為1,2,……,n。
從第2行到第n行,每行給出3個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和長度。例如,“2 4 7”表示連線結點2與4的邊的長度為7。
所給的資料都是爭取的,不必檢驗。
【輸出】
輸出檔案core.out只有一個非負整數,為指定意義下的最小偏心距。
【輸入輸出樣例】
【輸入輸出樣例1】
core.in Core.out
5 2
1 2 5
2 3 2
2 4 4
2 5 3 5
【輸入輸出樣例2】
core.in core.out
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3 5
【限制】
40%的資料滿足:5<=n<=15
70%的資料滿足:5<=n<=80
100%的資料滿足:5<=n<=300,0<=s<=1000。邊長度為不超過1000的正整數

Floyed的O(n^3)太暴力,但是考慮到是07年的題,但是肯定過不了。。
那麼O(n^2)的做法列舉直徑上的子路徑,然後求最大深度。
O(nlogn)的話,我用優先佇列維護當前最大可以優化的路徑,那麼維護dis陣列,表示當前子樹的最長路徑。
網上看到另一種做法,也是O(nlogn),先找出直徑,然後對於直徑上的點可以用資料結構來維護。。
我的做法:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) const int INF=0x3f3f3f3f; const int maxn = 305; struct Edge { int to,next; int val; }edge[maxn<<1]; int head[maxn]; int maxedge; inline void addedge(int u,int v,int c) { edge[++maxedge] = (Edge) { v,head[u],c }; head[u] = maxedge; edge[++maxedge] = (Edge) { u,head[v],c }; head[v] = maxedge; } int n,s; void init() { scanf("%d%d",&n,&s); memset(head,-1,sizeof(head)); maxedge=-1; for(int i=1;i<n;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); addedge(u,v,c); } } void Find(int,int); int dis[maxn]; bool chain[maxn]; // to mark if is on the chain int end1,end2; void dfs1(int u,int father,int deep,int &end) { dis[u] = deep; if(!end || dis[end]<dis[u]) end=u; for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==father) continue; dfs1(v,u,deep+edge[i].val,end); } } bool dfs2(int u,int father,int end,int half) { for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==father) continue; if(v==end || dfs2(v,u,end,half)) { if(half>=dis[u] && half<dis[v]) Find(u,v); return true; } } return false; } void dfs3(int u,int father) { for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==father) continue; dfs3(v,u); smax(dis[u],dis[v]+edge[i].val); } } bool dfs4(int u,int father,int end) { for(int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if(v==father) continue; if(v==end || dfs4(v,u,end)) { chain[u]=true; return true; } } return false; } int S,T; struct Info { int u,from,val,id; bool operator < (const Info t) const { return val < t.val; } }; priority_queue <Info> que; void Find(int u,int v) { int ans=INF,tmp=0; memset(dis,0,sizeof(dis)); dfs3(v,-1); // only node as v for(int i=head[v];~i;i=edge[i].next) smax(tmp,dis[edge[i].to]+edge[i].val); smin(ans,tmp); memset(dis,0,sizeof(dis)); dfs3(u,-1); S=T=u; tmp=0; for(int i=head[u];~i;i=edge[i].next) if(chain[edge[i].to]) que.push((Info){edge[i].to,u,dis[edge[i].to]+edge[i].val,i}); else smax(tmp,dis[edge[i].to]+edge[i].val); int totlens=0; while(!que.empty()) { Info now = que.top(); que.pop(); if(now.from^S && now.from^T) { smax(tmp,now.val); continue; } if(totlens+edge[now.id].val>s) { smin(ans,max(now.val,tmp)); printf("%d",ans); exit(0); } for(int i=head[now.u];~i;i=edge[i].next) { int v=edge[i].to; if(v==now.from) continue; if(chain[v]) que.push((Info){v,now.u,dis[v]+edge[i].val,i}); // dis is settled to be the left max_dis else smax(tmp,dis[v]+edge[i].val); } if(now.from==S) S=now.u; else T=now.u; totlens+=edge[now.id].val; } } void work() { end1=end2=0; dfs1(1,-1,0,end1); dfs1(end1,-1,0,end2); dfs4(end1,-1,end2); chain[end1]=true; chain[end2]=true; int half=dis[end2]>>1; dfs2(end1,-1,end2,half); } int main() { freopen("core.in","r",stdin); freopen("core.out","w",stdout); init(); work(); return 0; }