• 树形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
    ",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
    ",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
    ",Min,Max);
                len+=Min;
                temp2=Max;
    
                len=max(max(temp1,temp2),len);
                if(len<ans)
                    ans=len;
                //system("pause");
            }
            printf("Case %d: %d
    ",ca,ans);
    
        }
       return 0;
    }
    
    



  • 相关阅读:
    【每日日报】第四十六天
    jsp动作标识
    JSP注释
    request对象
    Servlet的创建和配置
    基于图书管理系统的浏览
    在JSP中应用JavaBean
    交流会
    基于图书管理系统的改
    基于图书管理系统的增
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3363425.html
Copyright © 2020-2023  润新知