洛谷 P1099 樹網的核

2022-04-04 15:54:09 字數 4139 閱讀 4600

設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 2 5

2 3 2

2 4 4

2 5 3

輸出樣例#1: 複製

5

輸入樣例#2: 複製

8 6

1 3 2

2 3 2

3 4 6

4 5 3

4 6 4

4 7 2

7 8 3

輸出樣例#2: 複製

5
40\%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

/*

可以想象出,這個樹網的核一定在這棵樹的直徑上(不一定對)

因為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

<

}

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 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

<

}

100

洛谷P1099 樹網的核

題目 對於這種題目描述比較長的題,可以考慮簡化題意。簡化後的題意 給定一棵帶邊權無根樹 在其直徑上求出一段長度不超過s的路徑f,使得離路徑距離最遠的點到路徑的距離最短。求最短距離。根據題目範圍,直接暴力floyd求多源最短路徑。然後 n 2 求出直徑和直徑端點。搜尋求出直徑上的點。然後再暴力找出所有...

洛谷 P1099 樹網的核 題解

樓上的大佬似乎都用的dfs,像我這種蒟蒻只會用暴力的floyd演算法。不過,看到這道題規模只有300,floyd演算法不會有問題。首先用floyd演算法預處理點對之間的距離,接下來窮舉每一對點構成的路徑 假裝每一條路徑就是樹網的核 如果路徑長 s,則計算其它點到該路徑的最大距離,取窮舉到的所有路徑中...

P1099 樹網的核

這裡是o n 2 的做法 首先可以證明,對於每一條直徑,求出的偏心距是一樣的 怎麼證明?顯然 我不會 怎樣求樹的直徑?簡單。貪心 在一條直徑上,顯然選擇的路徑越長越好 實現 首先求出樹上所有點之間的距離 n 2 一直dfs就行 然後找出直徑及直徑經過的點 最後在直徑上貪心的取即可 include i...