4.1 爬树

实验任务

YellowStar 拥有一棵\(n\)个结点的有根树,标号为 1 到\(n\),1 号结点为根结点,树的每个叶子结点有一只蚂蚁。每一秒钟每只蚂蚁可以选择不动或者爬到相邻的一个结点。除了根节点,其他结点每个时刻最多只能有一只蚂蚁,问开始后最少经过多少秒,所有蚂蚁都能爬到根节点。

数据输入

输入的第一行为数字\(n\ (2\leq n\leq 10^5)\),表示树的结点个数。接下来第\(n - 1\)行,每行包含 2 个整数\(u, v\ (1\leq u, v\leq n)\),表示树边(不保证\(u\)\(v\)的父亲,也有可能\(v\)\(u\)的父亲)。保证输入的必然是一棵树。

数据输出

输出一个整数,表示最少时间。

输入示例 输出示例
12
1 2
1 3
1 4
2 5
2 6
3 7
3 8
3 9
8 10
8 11
8 12
6
2
2 1
1

数据范围

\(80\%\)的得分点,\(n \leq 1000\)\(20\%\)的得分点,\(n \leq 100000\)

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 100005

inline int max(int a, int b){ return a < b ? b : a; }

class node{
public:
int value, deep;
node(int v, int d) :value(v), deep(d){}
};

class Tree{
public:
Tree(){}
Tree(int n){
for (int i = 0; i < maxn; ++i){
edges[i].clear();
hasParent[i] = false;
}
hasParent[1] = true;
}
void addEdge(int a, int b){
edges[a].push_back(b);
edges[b].push_back(a);
}
int solve(){
hasParent[1] = true;
int result = 0, leaves, i, j;
for (i = 0; i < edges[1].size(); ++i){
leaves = 0;
bfs(edges[1][i], leaves);
for (j = 1; j < leaves; ++j)
deeps[j] = max(deeps[j - 1] + 1, deeps[j]);
result = max(result, deeps[leaves - 1]);
}
return result;
}

void bfs(int &treeRoot, int& leaves){
queue<node>myqueue;
myqueue.push(node(treeRoot, 1));
while (!myqueue.empty()){
node root = myqueue.front();
myqueue.pop();
//叶子节点度为1
if (edges[root.value].size() == 1){
deeps[leaves++] = root.deep; continue;
}
for (int i = 0; i<edges[root.value].size(); ++i)
if (!hasParent[edges[root.value][i]]){
hasParent[edges[root.value][i]] = true;
myqueue.push(node(edges[root.value][i], root.deep + 1));
}
}
}
private:
vector<int> edges[maxn];
bool hasParent[maxn];
int deeps[maxn];
}tree;

int main(){
int n;
int a, b;
int i;
scanf("%d", &n);
for (i = 1; i < n; ++i){
scanf("%d%d", &a, &b);
tree.addEdge(a, b);
}
printf("%d\n", tree.solve());
return 0;
}

设计思路与复杂度分析

考虑贪心就是对于每一棵子树,使用后序遍历,让所有蚂蚁从下往上爬,记录每一只蚂蚁到达当前节点的时间。在非叶子节点合并该节点的所有子节点的蚂蚁的时候同时考虑重叠问题。其实最后就等于对深度归并排序的同时将重叠的往后推。所以可以考虑遍历所有节点的深度使用快排,然后再考虑重叠问题,这样效率会高很多!另一个优化是其实建树也是后序的,所以两个过程是可以合并的。还有一个优化是使用层次遍历,这样就不用对深度排序了。最后时间复杂度为\(O(n)\)

0%