設t=(v,e,w)t=(v,e,w)是乙個無圈且連通的無向圖(也稱為無根樹),每條邊到有正整數的權,我們稱tt為樹網(treebetwork
),其中vv,ee分別表示結點與邊的集合,ww表示各邊長度的集合,並設tt有nn個結點。
路徑:樹網中任何兩結點aa,bb都存在唯一的一條簡單路徑,用d(a, b)d(a,b)表示以a, ba,b為端點的路徑的長度,它是該路徑上各邊長度之和。我們稱d(a, b)d(a,b)為a, ba,b兩結點間的距離。
d(v, p)=\min\d(v,p)=min, uu為路徑pp上的結點。
樹網的直徑:樹網中最長的路徑成為樹網的直徑。對於給定的樹網tt,直徑不一定是唯一的,但可以證明:各直徑的中點(不一定恰好是某個結點,可能在某條邊的內部)是唯一的,我們稱該點為樹網的中心。
偏心距\mathrm(f)ecc(f):樹網t中距路徑f最遠的結點到路徑ff的距離,即
\mathrm(f)=\max\ecc(f)=max
任務:對於給定的樹網t=(v, e, w)t=(v,e,w)和非負整數ss,求乙個路徑ff,他是某直徑上的一段路徑(該路徑兩端均為樹網中的結點),其長度不超過ss(可以等於s),使偏心距ecc(f)ecc(f)最小。我們稱這個路徑為樹網t=(v, e, w)t=(v,e,w)的核(core
)。必要時,ff可以退化為某個結點。一般來說,在上述定義下,核不一定只有乙個,但最小偏心距是唯一的。
下面的圖給出了樹網的乙個例項。圖中,a-ba−b與a-ca−c是兩條直徑,長度均為2020。點ww是樹網的中心,efef邊的長度為55。如果指定s=11s=11,則樹網的核為路徑defg
(也可以取為路徑def
),偏心距為88。如果指定s=0s=0(或s=1s=1、s=2s=2),則樹網的核為結點ff,偏心距為1212。
輸入格式:
共nn行。
第11行,兩個正整數nn和ss,中間用乙個空格隔開。其中nn為樹網結點的個數,ss為樹網的核的長度的上界。設結點編號以此為1,2,…,n1,2,…,n。
從第22行到第nn行,每行給出33個用空格隔開的正整數,依次表示每一條邊的兩個端點編號和長度。例如,「2 4 7247」表示連線結點22與44的邊的長度為77。
輸出格式:
乙個非負整數,為指定意義下的最小偏心距。
輸入樣例#1: 複製
5 2輸出樣例#1: 複製1 2 5
2 3 2
2 4 4
2 5 3
5輸入樣例#2: 複製
8 6輸出樣例#2: 複製1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
540\%40%的資料滿足:5 \le n \le 155≤n≤15
70\%70%的資料滿足:5 \le n \le 805≤n≤80
100\%100%的資料滿足:5 \le n \le 300,0 \le s \le 10005≤n≤300,0≤s≤1000。邊長度為不超過10001000的正整數
noip 2007 提高第四題
公式:乙個點到a,b之間路徑的距離為 (dis[i][a]+dis[i][b]-dis[a][b])/2
/*84可以想象出,這個樹網的核一定在這棵樹的直徑上(不一定對)
因為n很小,可以與處理出任意兩點間的距離
*/#include
#include
#include
#include
#define maxn 310*2
using
namespace
std;
inttop[maxn];
intn,s,tot,bns,ans;
intmap[maxn][maxn];
intto[maxn],cap[maxn],net[maxn],head[maxn];
intdad[maxn],deep[maxn],siz[maxn],length[maxn];
void add(int u,int v,int
w)void dfs(int
now)
}void dfs1(int
now)
for(int i=head[now];i;i=net[i])
if(dad[now]!=to[i]&&t!=to[i])
dfs1(to[i]);
}int lca(int x,int
y)
if(deep[x]>deep[y]) swap(x,y);
returnx;}
int dfs2(int u,int v,int
now)
void work(int a,int
b)
if(map[a][b]>s) return
;
for(int i=1;i<=n;i++)
bns=max(bns,dfs2(a,b,i));
ans=min(ans,bns);
return;}
intmain()
for(int i=1;i<=n;i++) map[i][i]=0
;
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)
map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
dfs(
1);dfs1(1
); ans=0x7f7f7f7f
;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
work(i,j);
cout
<
}
/*100可以想象出,這個樹網的核一定在這棵樹的直徑上(不一定對)
因為n很小,可以與處理出任意兩點間的距離
*/#include
#include
#include
#include
#define maxn 310*2
using
namespace
std;
inttop[maxn];
intn,s,tot,bns,ans;
intmap[maxn][maxn];
intto[maxn],cap[maxn],net[maxn],head[maxn];
intdad[maxn],deep[maxn],siz[maxn],length[maxn];
void add(int u,int v,int
w)void work(int a,int
b)
if(map[a][b]>s) return
;
for(int i=1;i<=n;i++)
bns=max(bns,(map[i][a]+map[i][b]-map[a][b])/2
); ans=min(ans,bns);
return;}
intmain()
for(int i=1;i<=n;i++) map[i][i]=0
;
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)
map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
ans=0x7f7f7f7f
;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
work(i,j);
cout
<
}
洛谷P1099 樹網的核
題目 對於這種題目描述比較長的題,可以考慮簡化題意。簡化後的題意 給定一棵帶邊權無根樹 在其直徑上求出一段長度不超過s的路徑f,使得離路徑距離最遠的點到路徑的距離最短。求最短距離。根據題目範圍,直接暴力floyd求多源最短路徑。然後 n 2 求出直徑和直徑端點。搜尋求出直徑上的點。然後再暴力找出所有...
洛谷 P1099 樹網的核 題解
樓上的大佬似乎都用的dfs,像我這種蒟蒻只會用暴力的floyd演算法。不過,看到這道題規模只有300,floyd演算法不會有問題。首先用floyd演算法預處理點對之間的距離,接下來窮舉每一對點構成的路徑 假裝每一條路徑就是樹網的核 如果路徑長 s,則計算其它點到該路徑的最大距離,取窮舉到的所有路徑中...
P1099 樹網的核
這裡是o n 2 的做法 首先可以證明,對於每一條直徑,求出的偏心距是一樣的 怎麼證明?顯然 我不會 怎樣求樹的直徑?簡單。貪心 在一條直徑上,顯然選擇的路徑越長越好 實現 首先求出樹上所有點之間的距離 n 2 一直dfs就行 然後找出直徑及直徑經過的點 最後在直徑上貪心的取即可 include i...