hdu_2196 computer 树状dp经典入门题

弄了一天终于弄明白了。

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2196

题目意思:给你一棵树,求每个点可以到达的最远的距离。

题解:典型的树状dp题目,需要两次dfs过程即可正解。

hdu_2196 computer 树状dp经典入门题_第1张图片

例如求图中结点2可以到达的最远距离只能是2的子树(虚线部分)可以达到的最远距离或者2的父亲结点1(实线部分)可以到达的最远距离加上这两个点之间的距离,这就是本题的核心思想。

第一次dfs:找出每个点(形成的子树)可以到达的最远的距离和次远距离(虚线部分),这个过程比较容易理解就不做太多的解释。


第二次dfs:找出每个点的父亲可以到达的最大距离,但父亲的最远距离很有可能包括此节点在内,这也是为啥要求每个的次远距离。所以在转移时需要判断一下父亲结点的最远距离是否包括当前结点。

hdu_2196 computer 树状dp经典入门题_第2张图片

其中maxn[root]是根结点形成的子树可以到达的最远距离,smax[root]为次远距离,fat[root]为父亲结点可以到达的最远距离。


附上ac代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define For0(n) for(int i = 0; i < n; i++)
#define For1(n) for(int i = 1; i <= n; i++)
#define MAX 10020
using namespace std;
int n;
struct Edge
{
int to, length;
};
vector vec[MAX];
int maxn[MAX], smaxn[MAX], fat[MAX];//其中maxn[root]是根结点形成的子树可以到达的最远距离,smax[root]为次远距离,fat[root]为父亲结点可以到达的最远距离。
void dfs1(int root)
{
int num = vec[root].size();
int temp;
For0(num)
{
dfs1(vec[root][i].to);
temp = maxn[vec[root][i].to] + vec[root][i].length;
if (temp > maxn[root])
{
smaxn[root] = maxn[root];
maxn[root] = temp;
}
else if (temp > smaxn[root])
smaxn[root] = temp;
}
}
void dfs2(int root)
{
int num = vec[root].size();
For0(num)
{
if (maxn[root] == maxn[vec[root][i].to] + vec[root][i].length)
fat[vec[root][i].to] = max(fat[root] + vec[root][i].length,
smaxn[root] + vec[root][i].length);
else
fat[vec[root][i].to] = max(fat[root] + vec[root][i].length,
maxn[root] + vec[root][i].length);
dfs2(vec[root][i].to);
}
}

int main()
{
Edge temp;
int x;
while (scanf("%d", &n) != EOF)
{
memset(maxn, 0, sizeof(maxn));
memset(smaxn, 0, sizeof(smaxn));
memset(fat, 0, sizeof(fat));
for (int i = 2; i <= n; i++)
{
temp.to = i;
scanf("%d%d", &x, &temp.length);
vec[x].push_back(temp);
}
dfs1(1);
dfs2(1);
For1(n)
{
printf("%d\n", max(fat[i], maxn[i]));
}
For1(n)
vec[i].clear();
}


return 0;
}

你可能感兴趣的:(树状dp)