链接:https://ac.nowcoder.com/acm/contest/6874/A
来源:牛客网
题目描述
调查兵团第56次壁外调查将对巨木之森展开,已知巨木之森共有nn块区域和n-1n−1条道路,保证这nn块区域联通。为了调查结果尽可能准确,兵团会派遣若干支小分队调查巨木之森,派出的小分队需满足以下规定:
1.每支小分队都可以选择从任意一块区域出发,但各支小分队的出发区域必须互不相同。
2.每支小分队都必须遍历完nn块区域。
3.每支小分队的物资消耗量为其遍历完nn块区域的路程和。
现已知调查兵团的物资总量为mm,请问最多能派遣多少支小分队参与调查?
输入描述:
第一行两个正整数nn与mm,表示巨木之森的区域数和调查兵团的物资总量,其中:n\leq10^{5}n≤10
5
,m\leq10^{18}m≤10
18
。
接下来n-1n−1行,每行三个正整数uu,vv,ww,表示uu号区域和vv号区域之间有一条长为ww的道路。其中:u\leq nu≤n,v\leq nv≤n,w\leq10^{8}w≤10
8
。
输出描述:
输出最多能派遣的小分队数量。
示例1
输入
复制
3 6
1 2 1
2 3 1
输出
复制
2
说明
从1号区域出发,遍历完3块区域,物资消耗量最少为2。
从2号区域出发,遍历完3块区域,物资消耗量最少为3。
从3号区域出发,遍历完3块区域,物资消耗量最少为2。
故最多派遣2支小分队。
这个题很明显是先求出每个点走完所有点的花费,然后把这些花费从
小到大排序,然后贪心的看能有多少个点的和小于总物资。
难点在于如何求出每个点跑完整张图的花费,如果每个点都dfs一遍
的话,肯定会超时,于是我们发现每个点的花费为这个树的直径的
2倍减去他能到达的最远距离,因为最远的距离控制的走一次,其余
的距离要走过去再返回去。
先求出树的直径,在求直径的过程中,先走到最远的点,再从这个
最远的点dfs一次,一定可以走到直径的另外的一个点,这就是这
个树的直径,再从这两个点dfs一次,每个点到这个点的距离一定有一个是这个
点能走到的最远距离,取一个大的,然后就能求出每个点的花费。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int N = 100010, M = 2 * N;
int h[N], e[M], ne[M], w[M], idx;
int n, m;
int dist[N];
int dist1[N];
int dist2[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void add(int a, int b, int c){
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++;
}
void dfs(int u, int father, int distance){
dist[u] = distance;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs(j, u, distance + w[i]);
}
}
void dfs1(int u, int father, int dist[], int distance){
dist[u] = distance;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs1(j, u, dist, distance + w[i]);
}
}
signed main(){
n = read();
m = read();
memset(h, -1, sizeof h);
int sum = 0;
for (int i = 1; i < n; i ++){
int a, b, c;
a = read();
b = read();
c = read();
sum += c;
add(a, b, c), add(b, a, c);
}
sum *= 2;
dfs(1, -1, 0);
int u1 = 1;
for (int i = 2; i <= n; i ++){
if (dist[i] > dist[u1])
u1 = i;
}
dfs(u1, -1, 0);
int u2 = 1;
for (int i = 2; i <= n; i ++){
if (dist[i] > dist[u2]){
u2 = i;
}
}
dfs1(u1, -1, dist1, 0);
dfs1(u2, -1, dist2, 0);
for (int i = 1; i <= n; i ++){
dist[i] = max(dist1[i], dist2[i]);
}
for (int i = 1; i <= n; i ++){
dist[i] = (sum - dist[i]);
}
sort(dist + 1, dist + 1 + n);
int ans = 0;
sum = 0;
for (int i = 1; i <= n; i ++){
if (dist[i] + sum <= m){
ans ++;
sum += dist[i];
}
}
cout << ans << endl;
// return 0;
}