2019牛客暑期多校訓練營(第四場)A

2021-09-25 18:26:35 字數 1409 閱讀 4273

題意:給定n個頂點,n-1條邊權為1的邊,將各個頂點連成乙個最小生成樹,再給定乙個k,表示有多少個人,每個人都在特點的乙個頂點上,現在這些人要相會,求使得這些人能夠相聚在一起的最短時間。

看了標程,答案就是k個人當中那2個距離最遠的人的距離d,答案就是d/2向上取整。

證明:

必要性:k個人當中,最遠的那2個人u,v要相遇,則其中乙個必定至少要走⌈d/2⌉的步數。

充分性:我們取最遠那2個人u,v相會的那個點,這個點一定是該路徑上的中點或中點附近,設該點為point。假若有另外乙個人k,k到point的距離大於⌈d/2⌉,那麼u,v這兩個人的距離就不是所有人中最遠的了,這樣就與假設矛盾。

綜上,命題成立。

那麼這麼一轉化,其實本題求的就是一顆樹的直徑。

什麼是樹的直徑?樹的直徑就是:樹中距離最遠的兩個節點的距離。怎麼求樹的直徑呢?方法就是:先在樹中任意找一節點設為根v1,對其求bfs,求出v1到其它所有節點的距離,取其中最遠距離的節點為v2,再設v2為根,對其求bfs,求出v2到其它所有節點的距離,取其中最遠距離的節點v3,那麼v2與v3的距離就是樹的直徑了——兩遍bfs遍歷整棵樹就可以求出其直徑。

關於樹的直徑,還可參考以下部落格:

(樹的直徑性質及演算法證明)

**如下:

#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn=1e5+5;

const int inf=0x7f7f7f7f;

int head[maxn],cnt;

int n,k,k[maxn];

int dis[maxn];

bool vis[maxn];

struct road

;}r[2*maxn];

void addedge(int u,int v,int w)

void bfs(int s)

} }}int main()

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

scanf("%d",&k[i]);

bfs(k[1]); //第一次bfs的起點是任選的,啥都行

int v1=0,temp=0;

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

bfs(v1); //對v1進行bfs

int v2=0; temp=0;

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

printf("%d\n",(dis[v2]+1)/2); //v1到v2的距離向上取整即可

return 0;

}

2019牛客暑期多校訓練營(第四場

a meeting 答案為最遠關鍵點的距離的一半向上取整,也就是關鍵點的樹的直徑的一半向上取整。先考慮兩個點,他倆是最遠距離,那麼最短時間就是 d 2 在此基礎上再加乙個點 前提是加上這個點,後不影響初始條件,即初始的兩個點之間的距離最遠 那麼不會影響答案,因為他與另外兩個點的相會的時間必然小於 d...

牛客暑期多校訓練營B Boundary

給定n個點,然後確定乙個過原點的圓,要使這n個點盡可能多的存在與圓上,最後輸出最多的存在於圓上的點的個數 三點確定乙個圓,我們已知這個圓必定經過原點,所以再依次利用三點求圓心的公式列舉每兩個點與原點 三點不共線 確定的圓心,最後選擇確定次數最多的圓心構成的圓 include include incl...

2019牛客暑期多校訓練營(第九場)

d knapsack cryptosystem 折半搜尋,晚上又去看了挑戰程式設計,對於時間複雜度高的情況,可以通過犧牲空間來降低時間複雜度。先把前半部分所有可以組合的情況列舉出來,然後對於後半部分依次列舉,那麼複雜度變化為o 2 36 o 2 18 2 18log 18 顯然就可做了,折半的裸題。...