HDU 2169 Computer[树形dp]

Computer

时限:1000ms

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

题意:

给你一个树状的电脑网络,求出每个点到其他点的最短距离。

思路:

我做搜索的时候做过这道题,当时用三个bfs过掉了,树的直径过掉的,今天练习数位dp,所以用数位dp写。思路很清晰,从u点出发有两个状态,一个是向下的最短,一个是过父亲节点,向上的最短距离。对于向下的很好解决,先从根节点一层一层的推上去。但是对于过父亲节点的情况,当u为其父亲节点向下的最远路径上的一点的时候,可能是u->u的父亲节点->u->u的子节点。所以要记录u的子树的次远距离,这样就当上面的情况发生的时候我们选择次远的距离作为从该点出发的最远距离。

dp[u][0]表示u向下走的最远距离,dp[u][1]表示u向下走的次远距离,dp[u][2]表示向上走的最远距离。

#include "stdio.h"
#include "vector"
#include "string.h"
#include "algorithm"
using namespace std;
const int maxn = 10000 + 10;
int head[maxn];
struct node {
    int to, next, val;
} edge[maxn];
int tot = 0;
int dp[maxn][3];
void add_edge(int u,int v,int w) {
    edge[tot].to = v;  edge[tot].val = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs1(int u) {
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].to;
        dfs1(v);
        int sval = dp[v][0] + edge[i].val;
        if (sval >= dp[u][0]) {
            dp[u][1] = dp[u][0];
            dp[u][0] = sval;
        }
        else if (sval > dp[u][1]) dp[u][1] = sval;
    }
}
void dfs2(int u) {
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].to;
        if (dp[v][0] + edge[i].val == dp[u][0])
            dp[v][2] = max(dp[u][2], dp[u][1]) + edge[i].val;
        else
            dp[v][2] = max(dp[u][2], dp[u][0]) + edge[i].val;
        dfs2(v);
    }
}
void init() {
    memset(head, -1, sizeof(head));
    memset(dp, 0, sizeof(dp));
    tot = 0;
}
int main(int argc, char const *argv[])
{
    int n;
    while (scanf("%d", &n) != EOF) {
        init();
        for (int i = 2; i <= n; i++) {
            int u, w;
            scanf("%d%d", &u, &w);
            add_edge(u, i, w);
        }
        dfs1(1);  dfs2(1);
        for (int i = 1; i <= n; i++) {
            printf("%d\n", max(dp[i][0], dp[i][2]));
        }
    }
    return 0;
}

再附上曾经用树的直径A掉的代码。

#include <bits/stdc++.h>
#define MAXN 10010
using namespace std;
struct node{
    int from, to, val, next;
} edge[MAXN*2];
int dist1[MAXN], head[MAXN], edgenum, s, dist2[MAXN];
int ans;
bool vis[MAXN];
void init() {
    memset(head, -1, sizeof(head));
    edgenum = 0;
}
void addEdge(int x, int y, int z) {
    edge[edgenum].from = x;
    edge[edgenum].to = y;
    edge[edgenum].val = z;
    edge[edgenum].next = head[x];
    head[x] = edgenum++;
}
void bfs1(int x) {
    queue<int> que; ans = 0;
    memset(vis, false, sizeof(vis));
    memset(dist1, 0, sizeof(dist1));
    while (!que.empty()) que.pop();
    que.push(x); vis[x] = true;
    while (que.size()) {
        int a = que.front(); que.pop();
        for (int i = head[a]; i != -1; i = edge[i].next) {
            int b = edge[i].to;
            if (!vis[b] && dist1[b] < dist1[a] + edge[i].val) {
                dist1[b] = dist1[a] + edge[i].val;
                if(ans < dist1[b]) {
                    ans = dist1[b]; s = b;
                }
                vis[b] = true; que.push(b);
            }
        }
    }
}void bfs2(int x) {
    queue<int> que; ans = 0;
    memset(vis, false, sizeof(vis));
    memset(dist2, 0, sizeof(dist2));
    while (!que.empty()) que.pop();
    que.push(x); vis[x] = true;
    while (que.size()) {
        int a = que.front(); que.pop();
        for (int i = head[a]; i != -1; i = edge[i].next) {
            int b = edge[i].to;
            if (!vis[b] && dist2[b] < dist2[a] + edge[i].val) {
                dist2[b] = dist2[a] + edge[i].val;
                if(ans < dist2[b]) {
                    ans = dist2[b]; s = b;
                }
                vis[b] = true; que.push(b);
            }
        }
    }
}
int main() {
    int a, b, c, n, m;
    while (scanf("%d", &n) != EOF) {
        init();
        for (int i = 2; i <= n; i++) {
            scanf("%d%d", &a, &b);
            addEdge(i, a, b); addEdge(a, i, b);
        }
        bfs1(1); bfs1(s); bfs2(s);
        for (int i = 1; i <= n; i++) {
            printf("%d\n", max(dist1[i], dist2[i]));
        }
    }
    return 0;
}

时间: 2024-08-02 02:48:31

HDU 2169 Computer[树形dp]的相关文章

HDU 2196 Computer 树形DP经典题

链接:http://acm.hdu.edu.cn/showproblem.php? pid=2196 题意:每一个电脑都用线连接到了还有一台电脑,连接用的线有一定的长度,最后把全部电脑连成了一棵树,问每台电脑和其它电脑的最远距离是多少. 思路:这是一道树形DP的经典题目.须要两次DFS,第一次DFS找到树上全部的节点在不同子树中的最远距离和次远的距离(在递归中进行动态规划就可以),第二次DFS从根向下更新出终于答案.对于每次更新到的节点u,他的最远距离可能是来自u的子树,或者是u的父亲节点的最远

HDU 2196 Computer 树形DP 经典题

给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权,放在数组cost中 令tree(i)表示以节点i为根的子树 对于节点i,离该节点最远的点要不就是在tree(i)中,要不就是在father(i)上面 令: dp[i][1] : 在子树tree(i)中,离i最远的距离 dp[i][2] : 在子树tree(i)中,离i第二远的距离 (递推的时候需要)

hdu 1011(树形dp)

Mark.看着吴神博客写的,还未完全懂. 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string>

HDU 2196Computer(树形DP)

给你一颗边带权值的树,求树上的每一点距离其最远的一个点的距离 比较典型的题了,主要方法是进行两次DFS,第一次DFS求出每一个点距离它的子树的最远距离和次远距离,然后第二次DFS从父节点传过来另一侧的树上的距离它的最远距离进行一次比较便可得出任意点的最远距离了 之所以需要记录最远和次远是为了辨别父节点的最远距离是否是根据自己得来,如果是的话应该选择父节点的次远距离,保证结果的准确性 1 //#pragma comment(linker,"/STACK:102400000,102400000&qu

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

HDU 4714 Tree2cycle (树形DP)

题意:给定一棵树,断开一条边或者接上一条边都要花费 1,问你花费最少把这棵树就成一个环. 析:树形DP,想一想,要想把一棵树变成一个环,那么就要把一些枝枝叶叶都换掉,对于一个分叉是大于等于2的我们一定要把它从父结点上剪下来是最优的, 因为如果这样剪下来再粘上花费是2(先不管另一端),如果分别剪下来再拼起来,肯定是多花了,因为多了拼起来这一步,知道这,就好做了.先到叶子结点, 然后再回来计算到底要花多少. 代码如下: #pragma comment(linker, "/STACK:10240000

HDU 3899 简单树形DP

题意:一棵树,给出每个点的权值和每条边的长度, 点j到点i的代价为点j的权值乘以连接i和j的边的长度.求点x使得所有点到点x的代价最小,输出 虽然还是不太懂树形DP是什么意思,先把代码贴出来把. 这道题目的做法是:先进行一次DFS,以每个节点为根,求出它下面节点到它的数量和. 再进行一次DFS,以每个节点为根,求出它下面节点到它的花费总和. source code: #pragma comment(linker, "/STACK:16777216") //for c++ Compile

HDU 4313 Matrix 树形dp

题意: 给定n个点的树,m个黑点 以下n-1行给出边和删除这条边的费用 以下m个黑点的点标[0,n-1] 删除一些边使得随意2个黑点都不连通. 问删除的最小花费. 思路: 树形dp 每一个点有2个状态,成为黑点或白点. 若本身这个点就是黑点那么仅仅有黑点一种状态. 否则能够觉得是子树中某个黑点转移上来. 所以dp[i][0]是i点为黑点的状态. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <st

hdu-2169 Computer(树形dp+树的直径)

题目链接: Computer Time Limit: 1000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) 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 co