樹網的核-Floyd+寬搜
阿新 • • 發佈:2020-08-12
題目:
VIJOS-P1362 樹網的核
Time Limit: 1 SecMemory Limit: 128 MBDescription
設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
包含n行: 第1行,兩個正整數n和s,中間用一個空格隔開。其中n為樹網結點的個數,s為樹網的核的長度的上界。設結點編號以此為1,2,……,n。 從第2行到第n行,每行給出3個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和長度。例如,“2 4 7”表示連線結點2與4的邊的長度為7。 所給的資料都是正確的,不必檢驗。Output
只有一個非負整數,為指定意義下的最小偏心距。Sample Input
5 21 2 5
2 3 2
2 4 4
2 5 3
Sample Output
5 分析: 結論:選取任意直徑答案都相同#include<stdio.h> #include<queue> #include<cstring> using namespace std; queue<int>q; #define N 301 #define inf 10000001 int f[N][N]; int f1[N][N]; int dis[N]; int qu[N]; int node[N][N]; int end[N]; int point[N]; int vis[N]; int cnt=1; int n,s; int max(int x,int y) { return x>y?x:y; } int min(int x,int y) { return x<y?x:y; } int bfs(int x,int cnt) { memset(vis,0,sizeof(vis)); for(int i=1;i<=cnt;i++) vis[point[i]]=1; q.push(x); vis[x]=1; int re=0; while(!q.empty()) { int imp=q.front(); q.pop(); for(int i=1;i<=n;i++) { if(vis[i]==0&&f1[i][imp]!=inf) { dis[i]=dis[imp]+f1[i][imp]; re=max(dis[i],re); q.push(i); vis[i]=1; } } } return re; } int main() { scanf("%d%d",&n,&s); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) if(i!=j) f1[i][j]=f[i][j]=inf; } for(int i=1;i<n;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); f1[x][y]=f[x][y]=z; f1[y][x]=f[y][x]=z; } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { f[i][j]=min(f[i][j],f[i][k]+f[k][j]); } } } int d=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { d=max(d,f[i][j]); } } for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { if(f[i][j]==d) end[1]=i,end[2]=j; } } int ans=inf; for(int k=1;k<=n;k++) { if(f[end[1]][end[2]]==f[end[1]][k]+f[k][end[2]]&&k!=end[1]&&k!=end[2]) point[++cnt]=k; } point[1]=end[1]; point[++cnt]=end[2]; for(int i=1;i<=n;i++) dis[i]=bfs(i,cnt); for(int i=1;i<=cnt;i++) { int p=dis[point[i]]; for(int j=i;j<=cnt;j++) { if(f[point[i]][point[j]]>s) continue; if(p<dis[point[j]]) p=dis[point[j]]; int sr=max(f[point[i]][end[1]],f[point[j]][end[2]]); sr=max(sr,p); if(sr==0) continue; ans=min(sr,ans); // printf("%d p:%d %d\n",ans,point[i],point[j]); } } printf("%d",ans); }