HDU 3534 Tree (树形DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3534

 

题意:给出一颗树(n个顶点,n-1条边)

求最长的路径,以及最长路径的条数。

路径无非就是连接两个点直接的路。

因为是一颗树,所以连接两个点肯定是唯一的路径。

 

其实就是求两点间距离的最大值,以及这个最大值有多少个。

 

很裸的树形DP;

首先统计出结点到叶子结点的最长距离和次长距离。

 

然后找寻经过这个点的,在这个为根结点的子树中的最长路径个数目。

 

 

 

代码:

#include <string.h>

#include <iostream>

#include <algorithm>

#include <stdio.h>

using namespace std;

const int MAXN=100010;

const int INF=0x3f3f3f3f;

struct Node

{

    int to,next,len;

}edge[MAXN*2];

int head[MAXN];

int tol;

int maxn[MAXN];//该节点往下到叶子结点的最大距离

int smaxn[MAXN];// 次大距离

int maxn_num[MAXN];//最大距离的个数

int smaxn_num[MAXN];//次大距离的个数

int path[MAXN];//该结点为根的子树中,包含该结点的最长路径长度

int num[MAXN];//最长路径的长度



void init()

{

    tol=0;

    memset(head,-1,sizeof(head));

}

void add(int u,int v,int w)

{

    edge[tol].to=v;

    edge[tol].len=w;

    edge[tol].next=head[u];

    head[u]=tol++;

    edge[tol].to=u;

    edge[tol].len=w;

    edge[tol].next=head[v];

    head[v]=tol++;

}



void dfs(int u,int pre)

{

    maxn[u]=smaxn[u]=0;

    maxn_num[u]=smaxn_num[u]=0;

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

    {

        int v=edge[i].to;

        if(v==pre)continue;

        dfs(v,u);

        if(maxn[v]+edge[i].len>maxn[u])

        {

            smaxn[u]=maxn[u];

            smaxn_num[u]=maxn_num[u];

            maxn[u]=maxn[v]+edge[i].len;

            maxn_num[u]=maxn_num[v];

        }

        else if(maxn[v]+edge[i].len==maxn[u])

        {

            maxn_num[u]+=maxn_num[v];

        }

        else if(maxn[v]+edge[i].len>smaxn[u])

        {

            smaxn[u]=maxn[v]+edge[i].len;

            smaxn_num[u]=maxn_num[v];

        }

        else if(maxn[v]+edge[i].len==smaxn[u])

        {

            smaxn_num[u]+=maxn_num[v];

        }

    }

    if(maxn_num[u]==0)//叶子结点

    {

        maxn[u]=smaxn[u]=0;

        maxn_num[u]=smaxn_num[u]=1;

        path[u]=0;

        num[u]=1;

        return;

    }

    int c1=0,c2=0;

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

    {

        int v=edge[i].to;

        if(v==pre)continue;

        if(maxn[u]==maxn[v]+edge[i].len)c1++;

        else if(smaxn[u]==maxn[v]+edge[i].len)c2++;

    }

    path[u]=0;

    num[u]=0;

    if(c1>=2)//最长+最长

    {

        int tmp=0;

        path[u]=maxn[u]*2;

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

        {

            int v=edge[i].to;

            if(v==pre)continue;

            if(maxn[u]==maxn[v]+edge[i].len)

            {

                num[u]+=tmp*maxn_num[v];

                tmp+=maxn_num[v];

            }

        }

    }

    else if(c1>=1 && c2>=1)//最长+次长

    {

        path[u]=maxn[u]+smaxn[u];

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

        {

            int v=edge[i].to;

            if(v==pre)continue;

            if(maxn[u]==maxn[v]+edge[i].len)

            {

                num[u]+=maxn_num[v]*smaxn_num[u];

            }

        }

    }

    else//最长

    {

        path[u]=maxn[u];

        num[u]=maxn_num[u];

    }

}

int main()

{

    int n;

    while(scanf("%d",&n)==1)

    {

        int u,v,w;

        init();

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

        {

            scanf("%d%d%d",&u,&v,&w);

            add(u,v,w);

        }

        dfs(1,-1);

        int ans1=0,ans2=0;

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

        {

            if(path[i]>ans1)

            {

                ans1=path[i];

                ans2=num[i];

            }

            else if(path[i]==ans1)

                ans2+=num[i];

        }

        printf("%d %d\n",ans1,ans2);

    }

    return 0;

}

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(tree)