0%

树网的核 (NOIP2007)

设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenetwork),其中V, E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点。
路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a,b)表示以a,b为端点的路径的长度,它是该路径上各边长度之和。我们称d(a,b)为a,b两结点间的距离。
一点v到一条路径P的距离为该点与P上的最近的结点的距离:
d(v,P) = min{d(v,u),u为路径P上的结点}。
树网的直径:树网中最长的路径称为树网的直径。对于给定的树网T,直径不一定是唯一的,但可以证明:各直径的中点(不一定恰好是某个结点,可能在某条边的内部)是唯一的,我们称该点为树网的中心。
偏心距ECC(F):树网T中距路径F最远的结点到路径F的距离,即ECC(F)=min{d(v,F),v∈V}。
任务:对于给定的树网T=(V, E,W)和非负整数s,求一个路径F,它是某直径上的一段路径(该路径两端均为树网中的结点),其长度不超过s(可以等于s),使偏心距ECC(F)最小。我们称这个路径为树网T=(V,E,W)的核(Core)。必要时,F可以退化为某个结点。一般来说,在上述定义下,核不一定只有一个,但最小偏心距是唯一的。
下面的图给出了树网的一个实例。图中,A-B与A-C是两条直径,长度均为20。点W是树网的中心,EF边的长度为5。如果指定s=11,则树网的核为路径DEFG(也可以取为路径DEF),偏心距为8。如果指定s=0(或s=1、s=2),则树网的核为结点F,偏心距为12。

输入描述:

第1行,两个正整数n和s,中间用一个空格隔开。其中n为树网结点的个数,s为树网的核的长度的上界。设结点编号依次为1, 2, …, n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
所给的数据都是正确的,不必检验。

输出描述:

输出一个非负整数,为指定意义下的最小偏心距。

示例1
输入

5 2
1 2 5
2 3 2
2 4 4
2 5 3

输出

5

示例2
输入

8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3

输出

5

备注:

40%的数据满足:5 ≤ n ≤ 15
70%的数据满足:5 ≤ n ≤ 80
100%的数据满足:5 ≤ n ≤ 300, 0 ≤ s ≤ 1000。边长度为不超过1000的正整数

shuwangdehe.cppview raw
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;

const int N = 310, M = N*2;
int n,m;
int h[N], e[M], idx, ne[M], w[M];
int q[N], st[N], dist[N];
int pre[N];

typedef pair<int,int> PII;
vector<PII> path;

void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}


void bfs(int start){
int hh=0, tt =0;
q[0] = start;
memset(st, 0, sizeof st);
dist[start] = 0;
st[start] = true;
pre[start] = -1;
while(hh<=tt){
int u= q[hh++];
for(int i=h[u]; ~i; i = ne[i]){
int j = e[i];
if(!st[j]){
st[j] = true;
dist[j] = dist[u] + w[i];
q[++tt] = j;
pre[j] = u;
}
}
}
}


int get_max(){
int t = 1;
for(int i=1;i<=n;i++){
if(dist[i] > dist[t])
t = i;
}
return t;
}


int bfs_max(int u){
int hh=0, tt=0;
dist[u] = 0;
q[0] = u;
int res = 0;
while(hh<=tt){
int t= q[hh++];
res = max(res, dist[t]);
for(int i=h[t];~i;i=ne[i]){
int j = e[i];
if(!st[j]){
st[j] = true;
dist[j] = dist[t] + w[i];
q[++tt] = j;
}
}
}
return res;
}

bool check(int mid){
int u = 0, v = path.size()-1;
while(u+1<path.size() && path[u+1].second <= mid) u++;
while(v-1>=0 && path.back().second - path[v-1].second<=mid) v--;
if(u>v) return true;
if(path[v].second - path[u].second>m) return false;

memset(st, 0, sizeof st);
for(int i=0;i<path.size();i++) st[path[i].first] = true;
for(int i=u;i<=v;i++)
if(bfs_max(path[i].first) > mid) return false;
return true;
}



int main(){
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i=0;i<n-1;i++){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}

bfs(1);
int p = get_max();
bfs(p);
int v = get_max();

while(v!=-1){
path.push_back(make_pair(v, dist[v]));
v = pre[v];
}

reverse(path.begin(), path.end());
// for(int i=0;i<path.size();i++)
// printf("%d ", path[i].first);

int l = 0, r = 1e9;
while(l<r){
int mid = (l+r)>>1;
if(check(mid)) r = mid;
else l = mid+1;
}
printf("%d\n", r);
return 0;
}