您的位置:首页 > 其它

HDU2196 - Computer (树形DP)

2014-06-05 15:14 253 查看
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2196

【题意】题意好理解,就是有很多电脑(也就是结点)组成一颗树,每条边有一个权值(距离),求出每个节点能走到的最远的距离。

这里的输入有点蛋疼,看了半天也不知道,后来还是看了别人的题解才知道的。

输入的第一行不用说了,第二行开始每行的行号(从2开始,题目告诉你1号机器本来就有了)表示新加入的节点,他的父亲节点为第一个数,第二个数是边的权值

【分析】

这题是看了别人思路才写出来的,感觉对我刚刚学树形DP来说有点难度,就当开阔思维吧。

首先,很容易知道1号节点肯定为根节点,他没有父亲节点。然后考虑怎样算每个节点的最长路,因为是树形的,所以每个节点只有一个父亲节点,那么他的最大值来源只有两种可能--要么来自父亲节点,要么来自他的某个儿子节点。

这样我们只要分别算出每个节点往下走(也就是某个儿子节点)的最长路径和往上走(经过父亲节点)的最长路,最后比较下哪个长就可以了。

对于往下走(经过某个儿子节点):只要从叶子到根进行一次dfs,就可以算出每个节点通过其某个儿子的最长路,这个不难算。

但是对于往上走(经过父亲节点):也要用一次dfs,设当前子树根节点为r,儿子节点为s,怎样算出当前s通过其父亲节点r的最长路径呢?

首先当前边s-r肯定是会经过的,直接加上就行,然后就是求他的父亲的最长路径来自哪里:其实也只有两种可能--要么来自父亲节点,要么来自其他的儿子节点(当前儿子不能算)

所以dfs顺序为从根到叶子可以用dp[i]记录来自往上走最长距离,那么就解决了当前的来自父亲节点。那怎样算r节点除了s以外通过其他儿子的最长距离呢?在第一次dfs我们已经算出了每个节点往下走的最长距离,不是可以直接加上r往下走的最长距离不就行了么?但是仔细想想如果当前s是r的最长距离来源,那要怎么算?难道去掉吗?肯定不是。其实只要在第一次计算时在多算一个每个节点的次长距离和把最长距离来自哪个儿子节点记录下即可。这样的话,如果当前的s节点是r节点的最长路径来源的话只要加上他的用r的次长距离即可,因为s只有两种可能--要么是r的最长距离来源,要么不是。所以只需多一个次长距离就可以了。

那么这样的话就可以在最后比较每个节点往下走最大距离和往上走的最大距离,大的那个就是最终答案!

具体实现看代码吧

【AC代码】15ms

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define MAXN 10010
struct NODE{
int s, v;
NODE(int a, int b)//重载
{
s = a;
v = b;
}
};
int son[MAXN][2], dp[MAXN], p[MAXN];
//son[i][0]表示i节点为根的最长距离,son[i][1]是次长距离,p[i]记录i的最长距离来自那个儿子
//dp[i]是经过i的父亲的以及其父亲节点的其他儿子的路径的最长距离
vector<NODE> g[MAXN];

void dfs(int r)
{
int len = g[r].size();
for (int i = 0; i < len; i++)
{
int s = g[r][i].s;
dfs(s);
if (son[r][0] < son[s][0] + g[r][i].v)//求出当前r往下走的最大值以及最大值来自哪个儿子(不是叶子)
son[r][0] = son[s][0] + g[r][i].v, p[r] = s;
}
for (int i = 0; i < len; i++)//求出次大值
{
int s = g[r][i].s;
if (s == p[r]) continue;
son[r][1] = max(son[r][1], son[s][0] + g[r][i].v);
}
}
void dfs2(int r)//求出i往上走通过他父亲节点的其他儿子再往下走的最大值
{
int len = g[r].size();
for (int i = 0; i < len; i++)
{
int s = g[r][i].s;
if (s == p[r])//如果当前儿子是r的最大值来源,那么就取次大值和r通过父亲节点的最大值
dp[s] = max(son[r][1],dp[r])+g[r][i].v;
else
dp[s] = max(son[r][0],dp[r])+g[r][i].v;
dfs2(s);
}
}
int main()
{
#ifdef SHY
freopen("e:\\1.txt","r",stdin);
#endif
int n;
while (~scanf("%d%*c", &n))
{
int a, val;
for (int i = 0; i <= n; i++)
g[i].clear();
memset(son, 0, sizeof(son));
memset(dp,0,sizeof(dp));
for (int i = 2; i <= n; i++)
{
scanf("%d %d%*c", &a, &val);
g[a].push_back(NODE(i,val));
}
dfs(1);
dfs2(1);
for (int i = 1; i <= n; i++)
printf("%d\n", max(son[i][0],dp[i]));//每次比价i节点往上走大还是往下走大
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树形DP