Week6--作業 -- A -- 氪金帶東[樹直徑問題]

題目描述

實驗室裏原先有一臺電腦(編號爲1),最近氪金帶師咕咕東又爲實驗室購置了N-1臺電腦,編號爲2到N。每臺電腦都用網線連接到一臺先前安裝的電腦上。但是咕咕東擔心網速太慢,他希望知道第i臺電腦到其他電腦的最大網線長度,但是可憐的咕咕東在不久前剛剛遭受了宇宙射線的降智打擊,請你幫幫他。
在這裏插入圖片描述
提示: 樣例輸入對應這個圖,從這個圖中你可以看出,距離1號電腦最遠的電腦是4號電腦,他們之間的距離是3。 4號電腦與5號電腦都是距離2號電腦最遠的點,故其答案是2。5號電腦距離3號電腦最遠,故對於3號電腦來說它的答案是3。同樣的我們可以計算出4號電腦和5號電腦的答案是4.

輸入

輸入文件包含多組測試數據。對於每組測試數據,第一行一個整數N (N<=10000),接下來有N-1行,每一行兩個數,對於第i行的兩個數,它們表示與i號電腦連接的電腦編號以及它們之間網線的長度。網線的總長度不會超過10^9,每個數之間用一個空格隔開。

輸出

對於每組測試數據輸出N行,第i行表示i號電腦的答案 (1<=i<=N).

樣例輸入

5
1 1
2 1
3 1
1 1

樣例輸出

3
2
3
4
4

思路

綜述

這道題主要考察了一個新的知識:樹的直徑:
樹的直徑被定義爲樹中任意兩點之間距離的最大值
參考:圖的存儲和圖的遍歷

做法

1、從樹的任意一點開始遍歷這棵樹。找到的距離這個點最遠的點是樹的直徑的一個點;
2、從找到的這個點,開始遍歷這個樹,再找到的另一個點是該樹的直徑的另一個點;

本題

任取一點 1
dfs一次找到點v1
dfs兩次找到點v2,同時標記了其他所有點到v1的距離
dfs三次從v2開始,標記了其他所有點到v1的距離
最後輸出某個點到v1v2的最大距離即可

過程

Step1:初始化

採用前向星方式,不再贅述
參考:圖的存儲和圖的遍歷

const int maxn = 1e4 + 5;
struct Edge {
	int u, v, w, nxt;
}Edges[20020];
int head[maxn], tot;

void addEdge(int u, int v, int w) {
	Edges[tot].u = u;
	Edges[tot].v = v;
	Edges[tot].w = w;
	Edges[tot].nxt = head[u];
	head[u] = tot;
	tot++;
}
Step2:從1開始dfs

深度優先搜索
Step2.1:到達一點,標記

	vis1[u] = true;

Step2.2:遍歷該點的所有鄰接邊

	for (int i = head[u]; i != -1; i = Edges[i].nxt) {
	//找到一個未標記的點
		if (!vis1[Edges[i].v] ) {
			//標記
			vis1[Edges[i].v] = true;
			//記錄距離
			path1[Edges[i].v] = path1[u] + Edges[i].w;
			//記錄最大距離
			if (maxpath1 < path1[Edges[i].v]) {
				v1 = Edges[i].v;
				maxpath1 = path1[Edges[i].v];
			}
			//繼續進行
			dfs1(Edges[i].v);
		}
	}
Step3:從v1開始dfs

與找v1極爲類似

void dfs2(int u) {
	vis2[u] = true;
	for (int i = head[u]; i != -1; i = Edges[i].nxt) {
		if (!vis2[Edges[i].v]) {
			vis2[Edges[i].v] = true;
			path2[Edges[i].v] = path2[u] + Edges[i].w;
			if (maxpath2 < path2[Edges[i].v]) {
				v2 = Edges[i].v;
				maxpath2 = path2[Edges[i].v];
			}
			dfs2(Edges[i].v);
		}
	}
}
Step4:從v2開始dfs

與找v1極爲類似

void dfs3(int u) {
	vis3[u] = true;
	for (int i = head[u]; i != -1; i = Edges[i].nxt) {
		if (!vis3[Edges[i].v]) {
			vis3[Edges[i].v] = true;
			path3[Edges[i].v] = path3[u] + Edges[i].w;
			dfs3(Edges[i].v);
		}
	}

}

總結

這道題考察三個方面:
1、普通的dfs或者bfs遍歷算法
2、如何確定樹的直徑問題:兩次遍歷
3、多組數據之間是否合理的進行初始化


void init() {
	for (int i = 0; i < maxn; i++) {
		path1[i] = 0;
		path2[i] = 0;
		path3[i] = 0;
		vis1[i] = false;
		vis2[i] = false;
		vis3[i] = false;
		head[i] = -1;
	}
	maxpath1 = 0;
	maxpath2 = 0;
tot=0;
}

代碼

在上文中有詳細註釋,故不再贅述

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int N;
const int maxn = 1e4 + 5;
struct Edge {
	int u, v, w, nxt;
}Edges[20020];
int head[maxn], tot;

void addEdge(int u, int v, int w) {
	Edges[tot].u = u;
	Edges[tot].v = v;
	Edges[tot].w = w;
	Edges[tot].nxt = head[u];
	head[u] = tot;
	tot++;
}



int path1[maxn];
int path2[maxn];
int path3[maxn];
bool vis1[maxn];
bool vis2[maxn];
bool vis3[maxn];

int v1;
int v2;
int maxpath1 = 0;
int maxpath2 = 0;


void dfs1(int u) {
	vis1[u] = true;
	for (int i = head[u]; i != -1; i = Edges[i].nxt) {
		if (!vis1[Edges[i].v] ) {
			vis1[Edges[i].v] = true;
			path1[Edges[i].v] = path1[u] + Edges[i].w;
			if (maxpath1 < path1[Edges[i].v]) {
				v1 = Edges[i].v;
				maxpath1 = path1[Edges[i].v];
			}
			dfs1(Edges[i].v);
		}
	}
}

void dfs2(int u) {
	vis2[u] = true;
	for (int i = head[u]; i != -1; i = Edges[i].nxt) {
		if (!vis2[Edges[i].v]) {
			vis2[Edges[i].v] = true;
			path2[Edges[i].v] = path2[u] + Edges[i].w;
			if (maxpath2 < path2[Edges[i].v]) {
				v2 = Edges[i].v;
				maxpath2 = path2[Edges[i].v];
			}
			dfs2(Edges[i].v);
		}
	}
}

void dfs3(int u) {
	vis3[u] = true;
	for (int i = head[u]; i != -1; i = Edges[i].nxt) {
		if (!vis3[Edges[i].v]) {
			vis3[Edges[i].v] = true;
			path3[Edges[i].v] = path3[u] + Edges[i].w;
			dfs3(Edges[i].v);
		}
	}

}

void init() {
	for (int i = 0; i < maxn; i++) {
		path1[i] = 0;
		path2[i] = 0;
		path3[i] = 0;
		vis1[i] = false;
		vis2[i] = false;
		vis3[i] = false;
		head[i] = -1;
	}
	maxpath1 = 0;
	maxpath2 = 0;
tot=0;
}


int main() {
	while (cin >> N) {
		init();
		for (int i = 2; i <= N; i++) {
			int a, b;
			scanf("%d%d", &a, &b);
			addEdge(a, i, b);
			addEdge(i, a, b);
		}

		dfs1(1);
		dfs2(v1);
		dfs3(v2);
		for (int i = 1; i <= N; i++) {
			cout << max(path3[i], path2[i]) <<endl;
			//cout << path2[i] << " " << path3[i] << endl;
		}
	}
		
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章