1. 程式人生 > >HDU 3721 Building Roads(樹的中心)

HDU 3721 Building Roads(樹的中心)


3721 Building Roads

  Time Limit:16000/8000 MS (Java/Others)
  Memory Limit: 32768/32768 K (Java/Others)

Description

  There is a magic planet in the space. There is a magical country on the planet. There are N cities in the country. The country is magical because there are exactly N-1 magic roads between the N cities, and from each city, it is possible to visit any other city. But after the huge expansion of the country, the road system seems to be messy. The moderator decided to rebuild the road system.
As a worker, I cannot do too much things. I could just move one road to another position connecting arbitrary 2 cities using my magic, keeping its length unchanged. Of course, afterwards all the N cities have to be still connected. I wonder how to move in order to make the farthest distance between any two cities minimum. Could you solve it for me?
   

Input

  The first line of the input is one integer T (T ≤ 10), and then T test cases follow.
Each test case begins with a line contains only one integer N (N ≤ 2500), means there are N magic cities. The cities are numbered from 0 to N-1.
Following N-1 lines, each line has 3 integers a, b and c, means there is a magic road between a and b with distance c. (0 <= a, b < N, 0 < c <= 1000)
  

Output

  For each test case, output the case number and the corresponding minimum >farthest distance. See sample for detailed format.
  

Sample Input 1

  4
  0 1 2
  1 2 2
  2 3 2
  5
  0 1 1
  1 2 2
  2 3 3
  3 4 4
  

Sample Output 1

  Case 1: 4
  Case 2: 7

HINT

  

題目地址: 
HDU 3721 Building Roads

題解:

     
  題目大意:一棵樹斷掉一條邊,用此邊再連線兩個點,使得還是一棵樹,且使任意兩個點之間的最遠距離最小,求此距離
  要求即為直徑最小
  列舉斷邊,分成兩棵樹,連邊的兩個端點分別在兩棵樹上,考慮連哪兩個點
  樹的中心:這個點到樹的其他結點的最遠距離最近
  顯然就是連兩棵樹的中心了,那麼如何求樹的中心
  d1[u]表示以u為根的子樹中,u到葉子結點距離的最大值,用s1[u]記錄該葉子結點
  d2[u]表示以u為根的子樹中,u到葉子結點距離的次大值
  up[u]表示樹中除了以u為根的子樹中的葉子結點外,其他的葉子結點到u的最大值
  這些都非常好求
  樹的中心即為T[u]=max(d1[u],up[u])最小的點
  兩棵樹合併後的直徑有三種情況:樹1的直徑,樹2的直徑,兩個中心的T[u]相加+刪掉邊的長度
www.cnblogs.com/AGFghy/


AC程式碼

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,Q,num,d,ans1,ans2,ans;
int head[3005],Next[6005],point[6005],len[6005];
int a[5],u[3005],v[3005],l[3005],up[3005],d1[3005],d2[3005],s1[3005],belong[3005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
inline void add(int u,int v,int l)
{
    point[++num]=v;
    len[num]=l;
    Next[num]=head[u];
    head[u]=num;
}
void dfs1(int now,int pre,int kd)
{
    belong[now]=1-kd;
    for (int i=head[now]; i; i=Next[i])
    {
        int v=point[i];
        if (v==pre||v==a[kd]) continue;
        dfs1(v,now,kd);
        if (d1[now]<d1[v]+len[i])
        {
            d2[now]=d1[now]; 
            d1[now]=d1[v]+len[i]; s1[now]=v;
        }
        else
        if (d2[now]<d1[v]+len[i]) d2[now]=d1[v]+len[i];
    }
}
void dfs2(int now,int pre,int kd)
{
    for (int i=head[now]; i; i=Next[i])
    {
        int v=point[i];
        if (v==pre||v==a[kd]) continue;
        if (v!=s1[now]) up[v]=max(up[now],d1[now])+len[i];
        else up[v]=max(up[now],d2[now])+len[i];
        dfs2(v,now,kd);
    }
}
int main()
{
    Q=read(); 
    for (int cas=1; cas<=Q; cas++)
    {
        n=read();
        num=0;
        for (int i=1; i<=n; i++)
            head[i]=0;
        for (int i=1; i<=n-1; i++)
        {
            u[i]=read()+1; v[i]=read()+1; l[i]=read();
            add(u[i],v[i],l[i]); add(v[i],u[i],l[i]);
        }
        ans=1e9;
        for (int i=1; i<=n-1; i++)
        {
            memset(d1,0,sizeof(d1));
            memset(d2,0,sizeof(d2));
            memset(up,0,sizeof(up));
            a[0]=u[i]; a[1]=v[i]; 
            dfs1(a[0],0,1);  dfs2(a[0],0,1);
            dfs1(a[1],0,0); dfs2(a[1],0,0);
            d=0; ans1=ans2=1e9;
            for (int j=1; j<=n; j++)
                d=max(d,d1[j]+d2[j]);
            for (int j=1; j<=n; j++)
                if (belong[j]==0) ans1=min(ans1,max(up[j],d1[j]));
                else ans2=min(ans2,max(up[j],d1[j]));
            ans=min(ans,max(d,ans1+ans2+l[i]));
        }
        printf("Case %d: %d\n",cas,ans);
    }
    return 0;    
}