HDU3721 列舉 最長路

2021-06-18 10:43:12 字數 1132 閱讀 8758

題意:給你一顆n個節點n-1條邊的樹,每條邊都有乙個權值,現在讓你任意移動一條邊然後把這條邊連線到任意兩個點上,最後問你怎樣移動才能使樹上相距最遠的兩個點距離最小。

思路:先求出樹的最長路,然後列舉移動最長路上的所有邊,移走這條邊後,原樹必定分為不連線的兩顆子樹,分別求這兩顆子樹的最長路,然後分別找到兩顆子樹最長路上靠近中點的點,那麼最長路有三種情況:假設這條邊為 u -> v

1.u的左子樹的直徑;

2.v的右子樹的直徑;

3.u的左子樹的直徑上中點分割的最長路徑 +  v的右子樹的直徑上中點分割的最長路徑 + 邊權

每列舉一條邊,就取這三種情況的最大值;

需要注意的事:兩棵子樹的最長路,一定是以整棵樹的最長路的兩個端點為起始點的,因此只需要預處理出所有點到兩個端點的距離,然後根據刪除的最長路邊求兩顆子樹中的最大值即可。

所以我們只需2次bfs就夠了;

我感覺我的**很簡短:

#include #include #include #include using namespace std;

#define n 3000

int head[n],cnt;

void ini()

struct edge

e[n*2];

void add_edge(int a, int b, int c)

int dis1[n],dis2[n],fa2[n],vis[n],fa1[n],max_dis,max_id;

void bfs(int root, int dis, int fa)

{ max_dis=0;max_id=root;fa[root]=root;

memset(vis,0,sizeof(vis));

dis[root]=0;

queue q;

q.push(root);

while(!q.empty())

{int u=q.front();q.pop();

vis[u]=1;

for(int i = head[u]; i != -1; i = e[i].next)

{int v=e[i].to;

if(vis[v])continue;

dis[v]=dis[u]+e[i].w;

if(max_dis

HDU3721 列舉 最長路

題意 給你一顆n個節點n 1條邊的樹,每條邊都有乙個權值,現在讓你任意移動一條邊然後把這條邊連線到任意兩個點上,最後問你怎樣移動才能使樹上相距最遠的兩個點距離最小。思路 先求出樹的最長路,然後列舉移動最長路上的所有邊,移走這條邊後,原樹必定分為不連線的兩顆子樹,分別求這兩顆子樹的最長路,然後分別找到...

hdu 1692 列舉 剪枝

題意 給你一些井的資訊,井中原有的水,當井中的水滿足一定量後會被破壞並且這些水全部流入下乙個井中,用多少能量能直接破壞這個井。然後問要想破壞第n口井至少要多少能量。解題思路 這題首先是要找到從哪口井開始破壞,因為要破壞第n口井,要麼直接破壞n,要麼n之前有連續的幾口井一同被破壞,如果中間出現了乙個不...

完數(hdu1406)列舉

problem description 完數的定義 如果乙個大於1的正整數的所有因子之和等於它的本身,則稱這個數是完數,比如6,28都是完數 6 1 2 3 28 1 2 4 7 14。本題的任務是判斷兩個正整數之間完數的個數。input 輸入資料報含多行,第一行是乙個正整數n,表示測試例項的個數,...