牛客多校第四場 A meeting 樹的半徑

2022-08-01 19:09:13 字數 1783 閱讀 6329

題意:

有一棵樹,樹上有許多人,他們要聚會,找乙個點使得所有人到這個點的距離的最大值最小。

題解:首先,以乙個有人的點為根,求乙個生成樹,刪掉所有沒有人的子樹,保證所有的懸掛點(只連線一條邊的點)都是有人的節點,以保證後面求出的直徑的兩端是兩個有人節點。為什麼非得以有人的節點為根呢?因為如果找了乙個沒人的節點當根,而這個根又恰好是乙個懸掛點,那麼可以想象,這個懸掛點可能成為直徑的端點。

其次,求樹的直徑,就是樹上兩點的最長距離,這個直徑的兩個端點必然都是懸掛點。

直徑/2向上取整就是半徑,也就是題目所求距離。

求直徑可跑兩遍dfs,第一遍從任意點開始,找出與此點距離最大點,第二遍從這個點開始,找出與這個點距離最大點。

賽時想的是樹的重心,wa了,想像一棵樹上半部分是一條長鏈,下半部分是密密麻麻的兒子接在長鏈一端。然後又想了拓撲求直徑,t了。

但是發現拓撲排序的輪數其實就是樹的半徑,不知道這個結論有什麼用。

#include#include

#define inf 0x3f3f3f3f#include

#include

#include

using

namespace

std;

vector

lnk[100005

];vector

sclnk[100005];//

生成樹intn;

int scn;//

生成樹的節點數

bool ren[100005

];bool dfs(int fa,int

u) ok=ok||tr;

}return

ok;}

intkg;

void prt(int fa,int

u) kg--;}

bool vis[100005

];int size[100005];

int dis[100005

];struct

p p(

int n1,int

dis1)

friend

bool

operator >(const p &a,const p &b)

friend

bool

operator

<(const p &a,const p &b)};

void ddfs(int

st)

}} intmain()

intr1;

for(int i=1;i<=k;i++)

dfs(-1

,r1);

//prt(r1);

//求生成樹

memset(dis,inf,

sizeof

dis);

dis[r1] = 0

; ddfs(r1);

//求樹的直徑

int maxi=r1;

for(int i=1;i<=n;i++)

memset(dis,inf,

sizeof

dis);

memset(vis,

0,sizeof

vis);

dis[maxi] = 0

; ddfs(maxi);

int maxx=0

;

for(int i=1;i<=n;i++)

printf(

"%d\n

",(maxx+1)/2

);

return0;

}

2019牛客多校第四場 A meeting

考場上寫了一大坨樹形dp,寫的時候就感覺我這不是跟求樹的最長鏈寫的一毛一樣 然後考後看題解,果然是k個ren所連成的子樹的最長鏈的一半 可以利用反證法證明,如果在長度為d的最長鏈的中間放乙個中心,如果有另外乙個點到這個點的長度 d 1 2,那麼這個點到對面的那個點的長度大於d,所以不存在這樣乙個點。...

2019牛客多校第四場A meeting 思維

乙個樹上有若干點上有人,找出乙個集合點,使得所有人都到達這個點的時間最短 無碰撞 就是找樹的直徑,找直徑的時候記得要找有人的點 include include includeusing namespace std define pb push back define f first define s...

free(牛客多校第四場)

free 本題可以通過常規的最短路演算法改變來得到,通過在最短路演算法中加乙個長度為k的迴圈,判斷k條路免費後的最小權值即可。include include include include include include include include include define inf 0x3f...