HDU 2196 Computer
http://acm.hdu.edu.cn/showproblem.php?pid=2196
题意:
给出一棵树,求出每个点到其他点的最远距离。
思路:
对于每一个点,一方面它可以往它的子树方向走,另一方面可以往父亲结点的方向走。所以我们需要两次dfs,第一次用来求出每个点往其子树方向的最远距离和次远距离,为什么要计算出次远距离呢,因为在第二次dfs求父亲结点方向时,可能父亲结点的最大值经过了这个点,此时需要更换路线使得它不经过这个点。
#include<iostream> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; #define N 10001 int n; struct node { int to; //终点 int next; //下一条同样起点的边 int w; //权值 }edge[N*2]; int tol; int head[N]; //头结点,邻接链表存储 int dist[N][3]; //dist[N][0]代表正向最远距离,[N][1]代表正向次远距离,[N][2]代表反向最远距离 int flag[N]; //邻接链表存储,加入到链表的首部 void add_edge(int u, int v, int w) { edge[tol].to = v; edge[tol].w = w; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].w = w; edge[tol].next = head[v]; head[v] = tol++; } int dfs1(int u, int fa) { if (dist[u][0] != -1) return dist[u][0]; dist[u][0] = dist[u][1] = 0; for (int e = head[u]; e != -1; e = edge[e].next) { int v = edge[e].to; if (v == fa) continue; dfs1(v, u); if (dist[u][0] < dist[v][0] + edge[e].w) { flag[u] = v; dist[u][1] = dist[u][0]; //更新次远距离 dist[u][0] = dist[v][0] + edge[e].w; //更新最远距离 } //这个不能忘,比最远距离小但可能比次远距离大,此时需要更新次远距离 else if (dist[u][1] < dist[v][0] + edge[e].w) dist[u][1] = dist[v][0] + edge[e].w; } return dist[u][0]; } void dfs2(int u, int fa) { for (int e = head[u]; e != -1; e = edge[e].next) { int v = edge[e].to; if (v == fa) continue; if (v == flag[u]) dist[v][2] = max(dist[u][2], dist[u][1]) + edge[e].w; else dist[v][2] = max(dist[u][2], dist[u][0]) + edge[e].w; dfs2(v, u); } } int main() { //freopen("D:\\txt.txt", "r", stdin); int v, w; while (~scanf("%d", &n) && n) { tol = 0; memset(head, -1, sizeof(head)); memset(dist, -1, sizeof(dist)); memset(flag, -1, sizeof(flag)); for (int i = 2; i <= n; i++) { scanf("%d%d", &v, &w); add_edge(i, v, 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; }