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 =