HDU 3534 Tree(经典树形dp)

本文介绍了一种在一棵树上寻找最长路径及其数量的方法。通过一次深度优先搜索(DFS),记录每个节点作为根节点时到达叶子节点的最长及次长距离,并统计相应的数量。文章详细解释了如何通过这些信息来确定整棵树上的最长路径及其出现次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:在一棵树上找最长路径,和他出现的个数。

思路:有做过poj1985(求树直径)的基础,我们知道我们一遍dfs可以得到dp[i]表示i点为根的子树到叶子的最长距离,次长距离,同时我们还可以记载他们出现的数量。

我们可以先简单的分析,定义dp[i][0],dp[i][1]i点为根到叶子的最长,次长距离,dp[i][2],dp[i][3],表示他们出现的次数。如果对于某个节点,最长次长不相等(dp[i][0]!=dp[i][1]),那么经过这点的最长路径的个数就是他们乘积(dp[i][2]*dp[i][3]),反之,可以在转移过程中求得如果次长和最长相等的个数。

分析:转移过程具体看代码,思路很清晰。(懒)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
template<int N,int M>//N点的个数,M边的个数
struct Graph
{
    int top;
    struct Vertex{
        int head;
    }V[N];
    struct Edge{
        int v,next,w;
    }E[M];
    void init(){
        memset(V,-1,sizeof(V));
        top = 0;
    }
    void add_edge(int u,int v,int w){
        E[top].v = v;
        E[top].next = V[u].head;
        E[top].w=w;
        V[u].head = top++;
    }
};
const int N=1000000+10;
Graph<N,N*2> g;
int dp[N][5];
void dfs(int u,int f){
  dp[u][2]=1;dp[u][3]=1;
  for(int i=g.V[u].head;i!=-1;i=g.E[i].next){
    int v=g.E[i].v,w=g.E[i].w;
    if(v==f) continue;
    dfs(v,u);
    if(dp[v][0]+w==dp[u][0]){//如果根节点里最长的路径不只一条。
       dp[u][4]+=(dp[v][2]*dp[u][2]);//更新根到叶子节点里最长和次长相等的情况能组成的最长路径的个数
       dp[u][2]+=dp[v][2];//更新根到叶子节点里最长的个数
    }
    if(dp[v][0]+w==dp[u][1]) dp[u][3]+=dp[v][2];//更新根到叶子次长的个数
    if(dp[v][0]+w>dp[u][0]){//更新根到叶子节点最长边的权值和次数
        swap(dp[u][0],dp[u][1]);
        swap(dp[u][2],dp[u][3]);
        dp[u][0]=dp[v][0]+w;
        dp[u][2]=dp[v][2];
        dp[u][4]=0;
    }
    else if(dp[v][0]+w>dp[u][1]){//更新根到叶子节点次长边的权值和次数
        dp[u][1]=dp[v][0]+w;
        dp[u][3]=dp[v][2];
    }
  }
}

int n;

int main(){
   while(~scanf("%d",&n)){
      g.init();
      for(int i=0;i<n-1;i++){
        int a,b,c;scanf("%d%d%d",&a,&b,&c);
        g.add_edge(a,b,c);
        g.add_edge(b,a,c);
      }
      memset(dp,0,sizeof(dp));
      dfs(1,-1);
      int maxx=0;
      for(int i=1;i<=n;i++){
        if(dp[i][0]+dp[i][1]>maxx) maxx=dp[i][0]+dp[i][1];
      }
      int ans=0;
      for(int i=1;i<=n;i++){
        if(dp[i][0]+dp[i][1]==maxx){
            if(dp[i][0]==dp[i][1]) ans+=dp[i][4];
            else ans=dp[i][2]*dp[i][3];
        }
      }
      printf("%d %d\n",maxx,ans);
   }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值