Computer HDU - 2196 (树形dp || 树的直径)

博客讨论了如何使用树形动态规划(DP)解决求解树中每个节点到最远节点距离的问题。通过介绍DP状态的定义和转移,解释了如何计算每个节点的最大和次大距离,并强调了在更新过程中避免重复计数的关键点。此外,还提到了另一种方法,即直接寻找树的直径,即树上最长的简单路径,并解释了为何最远点会出现在直径的端点上。
摘要由CSDN通过智能技术生成

Computer HDU - 2196 (树形dp || 树的直径)

题目链接
题目大意:
给定一棵树,知道相邻结点的距离,问对于每一个结点,和距离它最远的结点之间的距离是多少。
Input:

5 n个结点
1 1 表示2和1之间的距离是1
2 1 表示3和2之间的距离是1
3 1 表示4和3之间的距离是1
1 1 表示5和1之间的距离是1

Output

3
2
3
4
4

题目思路:
有两种做法,一种是树的直径,一种是树形dp。先讲下树形dp。
dp[i][0] 从root节点更新过来的 这里的路一定和dp[i][1]不一样
dp[i][1] 子树的最大距离
dp[i][2] 子树的次大距离
1.很显然,对于一个结点,它的最长的距离有两种:一是它向下走,走到它子树的叶子结点,即dp[i][1]。第二种是从它的根过来的一条路,即dp[i][0]。因为这个结点的出路只有这两种,这样我们就很容易想到最终答案是取这两种的最大值了。
2.第一种我们发现很好求,就是一个dfs求深度的过程。
3.第二种我们发现可以从它的根节点推过来。比如说根是root,它的孩子有u1, u2, u3。这时我们要求dp[u1][0],root的路也是有两条, 一条是从root的父亲过来的路dp[root][0],一条是root的子树dp[root][1]。而dp[u1][0]是root的两条路的最大值。我们发现root的子树是包含u1的,所以dp[root][1]不一定对,因为dp[root][1] + w可能会算多,所以我们要分dp[root][1]是不是包含u1两种情况
就是说 当dp[root][1]不是包含u1时:dp[u1][0] = max(dp[root][1], dp[root][0]) + w
当dp[root][1]是包含u1时: dp[u1][0] = max(dp[root][2], dp[root][0]) + w
4.强调一下,这里的dp[root][2]虽然是root子树的次大值,但是这条路一定不会经过u1,为什么呢。
我们看下面的代码可以看出,更新root的最大次大值的时候,是直接比较的u1,u2,u3的大小,所以这里的次小值一定是可行的。
5.最后一点,怎么知道dp[root][1]包不包含u1,这也是我想了很久的一个问题。后来看了题解,如果说dp[root][1]包含u1的话, dp[u1][1] + dist(root, u1) 是等于 dp[root][1]的

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e4 + 100;
int data[maxn], dp[maxn][3];
bool vis[maxn];

//dp[i][0] 从root节点更新过来的
//dp[i][1] 子树的最大距离
//dp[i][2] 子树的次大距离

struct node
{
    int v, w;
};

vector<node> Edge[maxn];

int cnt = 0;
void dfs1(int root, int pre) {
   int biggest = 0, bigger =
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值