題意:給你一顆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,表示測試例項的個數,...