树的中心(树形DP)

本文介绍了如何利用深度优先搜索(DFS)算法,首先通过向下遍历计算每个节点的最大向下距离和次大距离,然后在向上遍历时更新子节点的最长可达距离。关键步骤包括标记叶节点、处理父子节点方向切换时的距离计算。代码展示了如何实现这一过程。
摘要由CSDN通过智能技术生成

传送门:树的中心

思路:第一遍向下深搜遍历,用子节点更新父节点,造出每一个向下的最大距离和次大距离,同时标记叶节点。

第二遍用父节点更新子节点,更新子节点向上的最大距离,相当于找父节点的其他方向向下的最大距离或向上的距离里面最大的一个。

如图在更新2的向上最大距离时,需要找到节点1向上0的方向或是向下3的方向里面距离最大的一个,然后加上1到2的距离作为2向上的最大距离

 

代码:

#include<iostream>
#include<cstring>
#include <cmath>
#include<algorithm>
#include <vector>
using namespace std;
const int N=1e4+7;
int n;
int ans;
bool st[N];
int d1[N],d2[N],p1[N],p2[N],up[N];
int idx,e[N*2],h[N],ne[N*2],w[2*N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dfs_d(int root,int father)//向下搜索最长路径和次长路径
{
    d1[root]=d2[root]=-0x3f3f3f3f;
    for(int i=h[root];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j==father)
            continue;
      int d= dfs_d(j,root)+w[i];
       if (d >= d1[root])
       {
           d2[root] = d1[root], d1[root] = d;
           p1[root]=j;
       }
        else if (d > d2[root])
        {
            d2[root] = d;
        }
    }
    if(d1[root]==-0x3f3f3f3f)
    {
        d1[root]=d2[root]=0;
        st[root]=true;
    }
    return d1[root];
}
//向上找最长路径,上一个点也有两个方向,要么向下要么向上,向下时要检查方向是否和来源相同,
//相同就次大和最大的另一个
void dfs_u(int root ,int father)
{
    for(int i=h[root];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j==father) continue;
        if(p1[root]==j) up[j]=max(up[root],d2[root])+w[i];
        else up[j]=max(up[root],d1[root])+w[i];
        dfs_u(j,root);
    }
}
int main()
{
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n-1;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dfs_d(1,-1);
    dfs_u(1,-1);
    int res=d1[1];
    for(int i=2;i<=n;i++)//遍历每一个点,叶节点就只有向上的选择
        if(st[i])
            res=min(res,up[i]);
        else
            res=min(res,max(d1[i],up[i]));
        cout<<res;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值