树形dp-hdu-3721-Building Roads

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3721

题目意思:

给一颗树,求移动一条边(边权值不变)到另外的位置,还是一棵树。求最小的树的直径。

解题思路:

充分利用树的直径的性质。

任何点的最远距离一定是树直径上的一个端点。

枚举每条边,分成两颗子树后,求出两颗子树的直径d1,d2,以及两颗树的任意点A的最大距离的最小值p1,p2.显然由树的直径的性质,知点A一定在树的直径上。

ans=min(ans,max(max(d1,d2),p1+p2+len)).

代码:

 

#include<iostream>

#include<cmath>

#include<cstdio>

#include<sstream>

#include<cstdlib>

#include<string>

#include<cstring>

#include<algorithm>

#include<vector>

#include<map>

#include<set>

#include<stack>

#include<list>

#include<queue>

#include<ctime>

#include<bitset>

#define eps 1e-6

#define INF 0x3f3f3f3f

#define PI acos(-1.0)

#define ll __int64

#define LL long long

#define lson l,m,(rt<<1)

#define rson m+1,r,(rt<<1)|1

#define M 1000000007

#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;



#define Maxn 3000

int cnt;

struct Edge

{

    int v,len;

    struct Edge * next;

}edge[Maxn<<1],*head[Maxn<<1];



void add(int a,int b,int len)

{

    ++cnt;

    edge[cnt].v=b,edge[cnt].len=len;

    edge[cnt].next=head[a];

    head[a]=&edge[cnt];

}

int ma[Maxn],mi[Maxn];

int Max,Min;



void dfs1(int cur,int fa)

{

    ma[cur]=mi[cur]=0;



    struct Edge * p=head[cur];

    while(p)

    {

        int v=p->v;



        if(v!=fa)

        {

            dfs1(v,cur);

            if(p->len+ma[v]>ma[cur])

            {

                mi[cur]=ma[cur];

                ma[cur]=p->len+ma[v];

            }

            else if(p->len+ma[v]>mi[cur])

                mi[cur]=p->len+ma[v];

        }

        p=p->next;

    }

}

void dfs2(int cur,int fa)

{

    if(ma[cur]>Max)

        Max=ma[cur];

    if(ma[cur]<Min)

        Min=ma[cur];



    struct Edge * p=head[cur];

    while(p)

    {

        int v=p->v;



        if(v!=fa)

        {

            if(p->len+ma[v]<ma[cur]) //最大距离不是从这个儿子过来的

                ma[v]=p->len+ma[cur];

            else if(p->len+mi[cur]>ma[v]) //最大距离就是这个儿子过来的

                ma[v]=p->len+mi[cur];

            else if(p->len+mi[cur]>mi[v])

                mi[v]=p->len+mi[cur];

            dfs2(v,cur);

        }

        p=p->next;

    }

}



int main()

{

    int t,n;



    scanf("%d",&t);

    for(int ca=1;ca<=t;ca++)

    {

        scanf("%d",&n);



        cnt=0;

        memset(head,NULL,sizeof(head));



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

        {

            int a,b,c;

            scanf("%d%d%d",&a,&b,&c);

            add(a,b,c);

            add(b,a,c);

        }

        int ans=INF;



        //printf("%d\n",cnt);

        for(int i=1;i<=cnt;i+=2)

        {   //相邻两个编号为一条边

            int u=edge[i].v,v=edge[i+1].v,len=edge[i].len;//枚举每一条边

            int temp1,temp2;



            //printf("u:%d v:%d\n",u,v);

            Max=0,Min=INF; //Max表示树的直径,Min表示最大距离的最小值

            dfs1(u,v);dfs2(u,v);



            len+=Min;

            temp1=Max;



            Max=0,Min=INF;

            dfs1(v,u),dfs2(v,u); //另外一颗子树

            //printf(":%d %d\n",Min,Max);

            len+=Min;

            temp2=Max;



            len=max(max(temp1,temp2),len);

            if(len<ans)

                ans=len;

            //system("pause");

        }

        printf("Case %d: %d\n",ca,ans);



    }

   return 0;

}




 


 

你可能感兴趣的:(Build)