Computer HDU - 2196(树形DP)

Computer HDU - 2196

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

题意:

给一棵树,求每个点到另一个点的最远的距离

分析:

题解分析转自传送门
分析:求一个树中所有节点能到达的最远距离。要用两个dfs。

首先第一个dfs求出所有每个节点i在其子树中的正向最大距离和正向次大距离和dist[i][0]和dist[i][1](如果i节点在子树中最大距离经过了2号儿子,那么次大距离就是不经过2号儿子的最大距离)。并且还要标记longest[i]=j表示节点i在其子树中的最大距离经过了节点j(即j是i的一个儿子)。

由上步我们获得了正向最大距离,正向次大距离和最大距离的儿子节点标记。画图可以知道我们建立的这棵树,i节点的最远距离只有两种选择:i节点所在子树的最大距离,或者i节点连接它的父节点所能到达的最大距离。(即前者往下走,后者先往上走之后很可能也往下走)

所以我们只要求出反向最大距离dist[i][2](即i节点往它的父节点走所能到达的最大距离)就可以知道i节点在整个树中能走的最大距离了。

dist[i][2]求法:i节点往它的父节j点走,如果它的父节点的正向最大距离不经过i的话,那么dist[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向最大距离+ W[i][j].

如果它的父节点的正向最大距离经过i的话,那么dist[i][2]要不就是它父节点的反向最大距离+W[i][j]要不就是它父节点的正向大距离+ W[i][j].

上面就是dfs2要求的值。最终f[i] = max(dist[i][0],dist[i][2])

code:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10000+200;
struct edge{
    int to;
    int nxt;
    int w;
}edges[MAXN*2];
int tot;
int head[MAXN];
void add_edge(int u,int v,int w){
    edges[tot].to = v;
    edges[tot].w = w;
    edges[tot].nxt = head[u];
    head[u] = tot++;
}
int dist[MAXN][3];//dist[i][0,1,2]分别表示正向最大距离,正向次大距离,反向最大距离
int longest[MAXN];

int dfs1(int u,int fa){
    if(dist[u][0] >= 0) return dist[u][0];//记忆化
    dist[u][0] = dist[u][1] = dist[u][2] = longest[u] = 0;

    for(int e = head[u]; e != -1; e = edges[e].nxt){
        int v = edges[e].to;
        if(v == fa) continue;

        if(dist[u][0] < dfs1(v,u) + edges[e].w){//如果比最大值大,更新最大值
            longest[u] = v;
            dist[u][1] = max(dist[u][1],dist[u][0]);
            dist[u][0] = dfs1(v,u) + edges[e].w;
        }
        else if(dist[u][1] < dfs1(v,u) + edges[e].w)//如果不能更新最大值但是能更新次大值,也得更新
            dist[u][1] = max(dist[u][1],dfs1(v,u) + edges[e].w);
    }
    return dist[u][0];
}

void dfs2(int u,int fa){
    for(int e = head[u]; e != -1; e = edges[e].nxt){
        int v = edges[e].to;
        if(v == fa) continue;
        if(v == longest[u]) dist[v][2] = max(dist[u][2],dist[u][1]) + edges[e].w;
        else dist[v][2] = max(dist[u][2],dist[u][0]) + edges[e].w;
        dfs2(v,u);
    }
}
int main(){
    int n;
    while(~scanf("%d",&n) && n){
        tot = 0;
        memset(dist,-1,sizeof(dist));
        memset(head,-1,sizeof(head));
        memset(longest,-1,sizeof(longest));
        for(int i = 2; i <= n; i++){
            int v,w;
            scanf("%d%d",&v,&w);
            add_edge(i,v,w);
            add_edge(v,i,w);
        }
        dfs1(1,-1);
        dfs2(1,-1);
        for(int i = 1; i <= n; i++){
            printf("%d\n",max(dist[i][0],dist[i][2]));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/82711168