HDU 2196 Computer(经典树形dp)

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

题意:

给你一个数n,表示有n台电脑,(然后从第二台电脑开始)比如题目的例子,接下来的一行的数是1,1,第一个1表示的是和电脑2连的电脑是1,第二个1表示它们之间的距离是1,然后接下来2,1表示的是和电脑3相连的是电脑2,他们的距离是1。题目让求的是每台电脑可以到达的最远距离。

思路:

  • dp[u][0]表示以u为根节点向下走的最远距离
  • dp[u][1]表示以u为根节点向下走的次远距离
  • dp[u][2]表示以u为根节点向上走的最远距离

显然最后对于u,它可以到达的最远距离是max(dp[u][0],dp[u][2])

对于u的子节点v,如果求v的dp[v][2],(u的dp[u][0],dp[u][1],dp[u][2]已经求出来了)有两种可能,如果u的正向最大距离经过v,那么v的dp[v][2]就是就得在u的dp[u][2]+w和dp[u][1]+w中比较出来了

if(mark[u]==v) //如果正向最大距离经过v结点的话
        {
            dp[v][2]=max(dp[u][2]+w,dp[u][1]+w);
        }

但是如果正向距离不经过v,那么v的dp[v][2]就是就得在u的dp[u][2]+w和dp[u][0]+w中比较出来了

 else
        {
            dp[v][2]=max(dp[u][0]+w,dp[u][2]+w);
        }

你要知道的一点是,在求子节点的反向最大距离时候,是根据父节点的正向最大(次大)距离和反向最大距离来求的

进行两次dfs(),第一次求dp[u][0]和dp[u][1],第二次dfs求dp[u][2],

有人会问对于u,v如果u的正向次大距离如果也经过v怎么办,这点的话在第一次用dfs的时候已经避免了这种情况,对于u的话求它的正向最大距离的时候,用的是他所有的子节点的正向最大距离,而没有用子节点的次大距离,所以就避免了子节点的次大距离成为父节点的次大距离

#include<stdio.h>
#include <iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
using namespace std;
const int maxn=10005;
int n,ant,sum;
int dp[maxn][3],head[maxn],mark[maxn];
struct lll
{
    int v,w,next;
}p[maxn*2];
void add(int u,int v,int w)
{
    p[ant].v=v;
    p[ant].w=w;
    p[ant].next=head[u];
    head[u]=ant++;
}
void init()
{
    memset(dp,0,sizeof(dp));
    memset(head,-1,sizeof(head));
    memset(mark,0,sizeof(mark));
    ant=0;
}
void dfs1(int u,int fa)
{
    int max1=0,max2=0;
    for(int i=head[u];i!=-1;i=p[i].next)
    {
        int v=p[i].v;
        if(v==fa)
            continue;
        dfs1(v,u);
        if(max1<dp[v][0]+p[i].w)
        {
            mark[u]=v;
             max2=max1;
            max1=dp[v][0]+p[i].w;
        }
        else if(max2<dp[v][0]+p[i].w)
        {
            max2=dp[v][0]+p[i].w;
        }
    }
    dp[u][0]=max1,dp[u][1]=max2;
}
void dfs2(int u,int fa)
{

    for(int i=head[u];i!=-1;i=p[i].next)
    {
        int v=p[i].v;
        if(v==fa)
            continue;
        int w=p[i].w;
        if(mark[u]==v)
        {
            dp[v][2]=max(dp[u][2]+w,dp[u][1]+w);
        }
        else
        {
            dp[v][2]=max(dp[u][0]+w,dp[u][2]+w);
        }
        dfs2(v,u);
    }

}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int u=2;u<=n;u++)
        {
            int v,w;
            scanf("%d%d",&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        dfs1(1,1);
        dfs2(1,1);
        for(int a=1;a<=n;a++)
        {
            printf("%d\n",max(dp[a][0],dp[a][2]));
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值