生活随笔
收集整理的這篇文章主要介紹了
树网的核(codevs 1167)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述?Description
【問題描述】
設 T=(V, E, W) 是一個無圈且連通的無向圖(也稱為無根樹),每條邊帶有正整數的權,我
們稱T 為樹網(treenetwork),其中V, E分別表示結點與邊的集合,W 表示各邊長度的集合,
并設T 有n個結點。
路徑:樹網中任何兩結點a,b 都存在唯一的一條簡單路徑,用d(a,b)表示以a,b 為端點的
路徑的長度,它是該路徑上各邊長度之和。我們稱d(a,b)為a,b 兩結點間的距離。
一點v到一條路徑P的距離為該點與P 上的最近的結點的距離:
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 Description
第1 行,兩個正整數n和s,中間用一個空格隔開。其中n 為樹網結點的個數,s為樹網的核
的長度的上界。設結點編號依次為1, 2, ..., n。
從第2 行到第n行,每行給出3 個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和
長度。例如,“2 4 7”表示連接結點2 與4 的邊的長度為7。
所給的數據都是正確的,不必檢驗。
輸出描述?Output Description
輸出只有一個非負整數,為指定意義下的最小偏心距
樣例輸入?Sample Input
【輸入樣例1】
5 2
1 2 5
2 3 2
2 4 4
2 5 3
【輸入樣例2】
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
樣例輸出?Sample Output
【輸出樣例1】
5
【輸出樣例1】
5
數據范圍及提示?Data Size & Hint
【限制】
40%的數據滿足:5<=n<=15
70%的數據滿足:5<=n<=80
100%的數據滿足:5<=n<=300, 0<=s<=1000。邊長度為不超過1000 的正整數
/*數據不大,所以按照題目要求去做就行了先floyed預處理出兩點間的距離,然后dfs求出直徑,最后搜索直徑上的每條路徑(很明顯在小于s的情況下越長越好),用每條路徑中的答案更新ans 。
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define INF 100000000
#define M 310
using namespace std;
int head[M],dis[M][M],a[M],vis[M],n,s,ans=
INF;
int cnt,maxn;
struct node
{int v,pre,t;
};node e[M*
2];
struct Node
{int lu[M],len;
};Node zh[M];
void add(
int i,
int x,
int y,
int z)
{e[i].v=
y;e[i].t=
z;e[i].pre=
head[x];head[x]=
i;
}
void floyed()
{for(
int k=
1;k<=n;k++
)for(
int i=
1;i<=n;i++
)for(
int j=
1;j<=n;j++
)if(i!=j&&i!=k&&j!=
k)dis[i][j]=min(dis[i][j],dis[i][k]+
dis[k][j]);
}
void find(
int x,
int t,
int Dis)
{for(
int i=head[x];i;i=
e[i].pre)if(!
vis[e[i].v]){vis[e[i].v]=
1;a[t]=
e[i].v;find(e[i].v,t+
1,Dis+
e[i].t);vis[e[i].v]=
0;}if(Dis>=
maxn){if(Dis>maxn)cnt=
1,maxn=
Dis;else cnt++
;zh[cnt].len=
t;for(
int i=
1;i<=t;i++
)zh[cnt].lu[i]=
a[i];}
}
void check(
int t)
{int ecc=
0;for(
int i=
1;i<=n;i++
)if(!
vis[i]){int p=
INF;for(
int j=
1;j<=t;j++
)p=
min(p,dis[i][a[j]]);ecc=
max(p,ecc);}ans=
min(ans,ecc);
}
void dfs(
int i,
int j,
int t,
int Dis)
{if(j==
zh[i].len){check(t);return;}if(Dis+dis[zh[i].lu[j]][zh[i].lu[j+
1]]>
s){check(t-
1);return;}if(j<
zh[i].len){vis[zh[i].lu[j+
1]]=
1;a[t]=zh[i].lu[j+
1];dfs(i,j+
1,t+
1,Dis+dis[zh[i].lu[j]][zh[i].lu[j+
1]]);}
}
int main()
{memset(dis,0x3f3f3f3f,
sizeof(dis));scanf("%d%d",&n,&
s);for(
int i=
1;i<n;i++
){int x,y,z;scanf("%d%d%d",&x,&y,&
z);add(i*
2-
1,x,y,z);add(i*
2,y,x,z);dis[x][y]=dis[y][x]=
z;}floyed();//求兩點間距離 for(
int i=
1;i<=n;i++)
//找出直徑
{memset(vis,0,
sizeof(vis));vis[i]=
1;a[1]=
i;find(i,2,
0);}for(
int i=
1;i<=cnt;i++)
//搜索直徑上的每條路徑
{for(
int j=
1;j<=zh[i].len;j++
){memset(vis,0,
sizeof(vis));vis[zh[i].lu[j]]=
1;a[1]=
zh[i].lu[j];dfs(i,j,2,
0);}}printf("%d",ans);return 0;
} View Code ?
轉載于:https://www.cnblogs.com/harden/p/5895533.html
總結
以上是生活随笔為你收集整理的树网的核(codevs 1167)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。