程序设计思维Week6-作业
A-氪金带东
Description
实验室里原先有一台电脑(编号为1),最近东东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度。
要求输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。
对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N)。
Sample
样例输入对应这个图,从这个图中你可以看出,距离1号电脑最远的电脑是4号电脑,他们之间的距离是3。 4号电脑与5号电脑都是距离2号电脑最远的点,故其答案是2。5号电脑距离3号电脑最远,故对于3号电脑来说它的答案是3。同样的我们可以计算出4号电脑和5号电脑的答案是4。
Input:
5
1 1
2 1
3 1
1 1
Output:
3
2
3
4
4
Idea
由题可知我们要求每个节点与可以到达的最远端的距离,“每台电脑都用网线连接到一台先前安装的电脑上”表明这张图是一棵树,电脑就是树的节点。
首先我们要求这棵树的直径,即树中任意两点之间距离的最大值,可以知道树的直径一定是某两个叶子之间的距离。我们用前向星存储树中的边。在接下来搜索点的过程中,我们都使用DFS,并用一个path数组记录每个点与起点的距离。第一次遍历,我们从树中任意一个节点开始用DFS搜索距离该点最远的叶子v1。第二次遍历,我们再从v1开始DFS搜索距离v1最远的另一个叶子v2,他俩的距离就是树的直径。求出树的直径后,我们可以推断树中任意一点可到达的最远端只可能是v1或v2,由于在第二次遍历中我们已经用一个path数据记录了每个点与v1的距离,所以我们只需要在第三次遍历中从v2开始进行DFS,用另一个path记录每个点与v2的距离,对于每个点,取与v1的距离、与v2的距离的最大值,就是我们要求第i台电脑到其他电脑的最大网线长度。
三次遍历中,前两次遍历因为需要找到最远端的顶点v1与v2,所以需要用变量实时记录更新当前搜索到的最远端和对应长度。三次遍历都需要记录每个点与起点的距离长度,长度等于前一个点与起点的距离+新边的边权。
Summary
这题是前向星+DFS的应用。我们要知道树中任意两点之间距离的最大值一定是某两个叶子间的距离,而每个点能到达的最远端一定是这两个叶子其中之一。我们需要三次DFS遍历,找到两个叶子,以及每个点分别与两个叶子的距离。
要为三次遍历都分别提供需要的数组或每次遍历前进行正确的初始化。同时要注意边的数目,以防数组越界
Codes
#include <iostream>
#include <algorithm>
using namespace std;
int n;
struct Edge {
int u, v, w, next;
}edge[20020];
int head[10020],path[10020], path1[10020], path2[10020], tot=0,v1,v2,t1,t2;
bool vis[10020];
void init(int n) {
tot = 0;
t1 = t2 = 0;
for (int i = 1; i <= n; i++)
{
head[i] = -1;
vis[i] = false;
path[i] = 0;
path1[i] = 0;
path2[i] = 0;
}
}
void addEdge(int u, int v, int w) {
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot;
tot++;
}
void dfs(int u) {
vis[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) {
int p = edge[i].v;
if (!vis[p]) {
vis[p] = true;
path[p] = path[u] + edge[i].w;
if (path[p] > t1) {
t1 = path[p];
v1 = p;
}
dfs(p);
}
}
}
void dfs1(int u) {
vis[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) {
int p = edge[i].v;
if (!vis[p]) {
vis[p] = true;
path1[p] = path1[u] + edge[i].w;
if (path1[p] > t2) {
t2 = path1[p];
v2 = p;
}
dfs1(p);
}
}
}
void dfs2(int u) {
vis[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) {
int p = edge[i].v;
if (!vis[p]) {
vis[p] = true;
path2[p] = path2[u] + edge[i].w;
dfs2(p);
}
}
}
int main()
{
cin.sync_with_stdio(false);
while (scanf("%d", &n) != EOF) {
init(n);
for (int i = 2; i <= n; i++) {
int u, w;
cin >> u >> w;
addEdge(u, i, w);
addEdge(i, u, w);
}
dfs(0);
memset(vis, false, sizeof(vis));
dfs1(v1);
memset(vis, false, sizeof(vis));
dfs2(v2);
for (int i = 1; i <= n; i++)
cout << max(path1[i], path2[i]) << endl;
}
}