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;
}
人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想
原文地址:https://www.cnblogs.com/kuangbin/p/3105215.html