HDU2196 - Computer(树形DP)

题目大意

给定一颗n个结点的树,编号为1~n,要求你求出每个结点能到达的最长路径

题解

用动态规划解决的~~~~把1 当成树根,这样就转换成有根树了。我们可以发现,对于每个结点的最长路,要么是从子树得到要么是从父亲得到我们用数组f,g,h分别记录从当前结点到子树能够获得的最大值和第二大值以及从当前结点到祖先能够获得的最大值。我们先进行一次dfs,把f和g值求出来,然后再进行一次dfs求出h的值来,对于h值,得分两种情况,对于当前结点s的h值,如果它的父亲得最长路径没有经过结点s,假设父亲结点为v,那么h的值为dis(s,v)+max(f[v],h[v]),否则的话h的值为dis(s,v)+max(g[v],h[v])

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define  MAXN 10005
vector<int>ivec[MAXN],value[MAXN];
int  f[MAXN],g[MAXN],h[MAXN];
int son[MAXN];
int dfs1(int root)
{
    if(f[root]) return f[root];
    if(ivec[root].empty()) return 0;
    int len=ivec[root].size();
    for(int i=0; i<len; i++)
        if(dfs1(ivec[root][i])+value[root][i]>f[root])
        {
            f[root]=f[ivec[root][i]]+value[root][i];
            son[root]=ivec[root][i];
        }
    for(int i=0; i<len; i++)
        if(ivec[root][i]!=son[root]&&f[ivec[root][i]]+value[root][i]>g[root])
            g[root]=f[ivec[root][i]]+value[root][i];
    return f[root];
}
void dfs2(int root)
{
    if(ivec[root].empty()) return;
    int len=ivec[root].size();
    for(int i=0; i<len; i++)
    {
        if(ivec[root][i]!=son[root])
            h[ivec[root][i]]=value[root][i]+max(f[root],h[root]);
       else
            h[ivec[root][i]]=max(g[root],h[root])+value[root][i];
        dfs2(ivec[root][i]);
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1; i<=n; i++)
        {
            ivec[i].clear();
            value[i].clear();
        }
        for(int i=2; i<=n; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            ivec[a].push_back(i);
            value[a].push_back(b);
        }
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        memset(h,0,sizeof(h));
        f[1]=dfs1(1);
        dfs2(1);
        for(int i=1;i<=n;i++)
        printf("%d\n",max(f[i],h[i]));
    }
    return 0;
}

posted on 2013-11-11 01:00  仗剑奔走天涯  阅读(212)  评论(0编辑  收藏  举报

导航