题目
实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。
Input
输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。
Output
对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N).
Sample Input
5
1 1
2 1
3 1
1 1
Sample Output
3
2
3
4
4
思路
一、链式前向星
图有三种存储方式:邻接矩阵、邻接表和链式前向星。
链式前向星与邻接表相类似。链式前向星由数组Head和结构体数组Edges构成,如图:
二、解题
由题可知,连接的网路呈一个树状的结构,树的直径的定义为:
树中任意两点之间距离的最大值
如图,从V1到V2的路径是树的直径。
首先选择某一点X,进行DFS搜索,直到最深的点,可以证明,这个点一定是树的直径的两端的其中一点,如图中的V2:
再从V2进行DFS搜索,直到最深的点,则这个点一定V1。
所以,在一棵树中,对于某一点X,离这个X最远的点一定要么是V1,要么是V2。
算法如下:
① 选定某一点(如1号点),进行DFS搜索,找到最深的点,设该点为V1。
② 从V1开始,进行DFS搜索,找到最深的点,设该点为V2。在进行DFS搜索时,计算每个点到V1的距离,将距离存放在数组dist1中。
③ 再从V2开始,进行DFS搜索。在进行DFS搜索时,计算每个点到V2的距离,将距离存放在数组dist2中。
④ 计算每个点到其他点的最大距离:i号点到其他点的最大距离为MAX(dist1[i], dist2[i])。
代码
#include <iostream>
#include <algorithm>
#define MAX 100100
// 由题意,这是一棵树,故有MAX个顶点,MAX-1条边
using namespace std;
int N;
// Edge[0]不用
struct Edge {
int to, weight, next;
}Edges[MAX];
int head[MAX];
bool visit[MAX];
int dist1[MAX];
int dist2[MAX];
int edgeNum;
int remote;
void addEdge(int u, int v, int w)
{
Edges[edgeNum].to = v;
Edges[edgeNum].weight = w;
Edges[edgeNum].next = head[u];
head[u] = edgeNum;
edgeNum++;
}
// DFS算法找最远的点
void DFS(int sorce, int length, int* dist)
{
dist[sorce] = length;
visit[sorce] = true;
if (dist[remote] < dist[sorce]) remote = sorce;
for (int i = head[sorce]; i != 0; i = Edges[i].next) {
if (!visit[Edges[i].to]) {
visit[Edges[i].to] = 1;
DFS(Edges[i].to, length + Edges[i].weight, dist);
}
}
}
int main()
{
while (cin >> N) {
memset(head, 0, sizeof(head));
edgeNum = 1;
for (int i = 2; i <= N; i++)
{
int v, w;
cin >> v >> w;
addEdge(i, v, w);
addEdge(v, i, w);
}
remote = 1;
memset(visit, false, sizeof(visit));
DFS(remote, 0, dist1);
memset(visit, false, sizeof(visit));
DFS(remote, 0, dist1);
memset(visit, false, sizeof(visit));
DFS(remote, 0, dist2);
for (int i = 1; i <= N; i++)
cout << max(dist1[i], dist2[i]) << endl;
}
return 0;
}