HDU2196-Computer(树形dp)

原题传送门

Computer

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 31201    Accepted Submission(s): 3989


Problem Description
A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.


Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.
 

Input
Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.
 

Output
For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).
 

Sample Input
  
  
5 1 1 2 1 3 1 1 1
 

Sample Output
  
  
3 2 3 4 4
 

Author
scnu
 


题目大意:
给你一棵树,每条边都有长度,求任意一个点可以到达的最远距离

输入:
5   //一共有五个点 
1 1   //第1条边为1->2,距离为1
2 1   //第2条边为2->3,距离为1
3 1   //第3条边为3->4,距离为1
1 1   //第4条边为1->5,距离为1


思路:
这是我做的树形dp的第二道题,说实话看了很久才弄懂,话不多说了来看一下做法吧
1.
首先思考下,一颗树的最远距离,是不是有两种可能,这里借用了大佬的一个图
如图,拿结点2来说,他的最远距离有两种可能,(1)他到叶子结点的最远距离L1   (2)(他的父节点(即结点1)到叶子结点的最远距离+父节点与它的距离)L2  那么他的最远距离就是max(L1,L2);
上面那里可能说的不是很清楚,可以这样理解:为方便叙述,将当前结点称为i其父亲结点为j;
L1为以i为根的子树中i的最远距离
L2为以j为根的子树(这个子树不能含有i)中j的最远距离+j到i的距离
2.
那么如何求L1与L2呢
L1:
L1好说,dfs一遍树,找到每个结点到叶子结点的最远距离即可,我们这里记为dp[i][0]表示i节点到叶子结点的最远距离;
我们这里再保存一个dp[i][1]表示i结点到叶子结点的次远距离,至于它有什么作用,我们稍后再说;
L2:
这时我们用dp[i][2]来表示L2,这时dp[j][1]就派上用场了,因为dp[j][0]保存的是j到叶子结点的最远距离,此时我们不能直接用,因为这个最远距离可能经过了i,我们先判断是否经过i,如果没有经过那么dp[i][2]=dp[j][2]+len(j->i),若经过了那么dp[i][2]=dp[j][1]+len(j->i);
void dfs2(int u)
{
    for(int i=0;i<xs[u].size();i++)
    {
        int to=xs[u][i].to;
        int val=xs[u][i].val;
        dp[to][2]=max(dp[u][2],dp[to][0]+val==dp[u][0]?dp[u][1]:dp[u][0])+val;
        dfs2(to);
        //判断从父节点到叶子结点的最远距离是否经过当前点,若经过则取父节点的次大距离
        //最后加上父节点到当前点的距离即为当前点从父节点过来的最大距离
    }
}
最后比较dp[i][0]与dp[i][2]即可;
PS:还是感觉没说清楚....

代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
using namespace std;
const int maxn = 10010;
int dp[maxn][4]; //dp[i][0]--i到叶子节点的最远距离 dp[i][1]--第二远距离 dp[i][2]从父节点到叶子结点的最大距离(不经过当前点
typedef struct{
    int to;  //到下一个点
    int val;  //到下一个点的距离
}NODE;
vector<NODE>xs[maxn];
void dfs1(int u)
{
    int max1=0;  //最大距离
    int max2=0;  //第二大距离
    for(int i=0;i<xs[u].size();i++)
    {
        NODE next=xs[u][i];
        dfs1(next.to);   //DFS下一个点
        int nowmax=dp[next.to][0]+next.val;  //当前所保存的最大距离
        if(max1<=nowmax)  //当前最大距离大于最大距离
        {
            max2=max1;         //更新最大距离与次大距离
            max1=nowmax;
        }
        else if(max2<nowmax)   //当前最大距离大于次大距离但是小于最大距离
        {
            max2=nowmax;       //更新次大距离
        }
    }
    dp[u][0]=max1;       //更新DP数组
    dp[u][1]=max2;
}
void dfs2(int u)
{
    for(int i=0;i<xs[u].size();i++)
    {
        int to=xs[u][i].to;
        int val=xs[u][i].val;
        dp[to][2]=max(dp[u][2],dp[to][0]+val==dp[u][0]?dp[u][1]:dp[u][0])+val;
        dfs2(to);
        //判断从父节点到叶子结点的最远距离是否经过当前点,若经过则取父节点的次大距离
        //最后加上父节点到当前点的距离即为当前点从父节点过来的最大距离
    }
}
int main()
{
    int N;
    scanf("%d",&N);
    for(int i=2;i<=N;i++)
    {
        int to,val;
        scanf("%d %d",&to,&val);
        NODE x;
        x.to=i;
        x.val=val;
        xs[to].push_back(x);
    }
    memset(dp,0,sizeof(dp));
    dfs1(1);
//    cout<<"ok1"<<endl;
    dfs2(1);
//    cout<<"ok2"<<endl;
    for(int i=1;i<=N;i++)
    {
        printf("%d\n",max(dp[i][0],dp[i][2]));
    }
    for(int i=1;i<=N;i++)
        xs[i].clear();
}



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值