题目描述
调查兵团第56次壁外调查将对巨木之森展开,已知巨木之森共有n块区域和n-1条道路,保证这n块区域联通。为了调查结果尽可能准确,兵团会派遣若干支小分队调查巨木之森,派出的小分队需满足以下规定:
1.每支小分队都可以选择从任意一块区域出发,但各支小分队的出发区域必须互不相同。
2.每支小分队都必须遍历完nn块区域。
3.每支小分队的物资消耗量为其遍历完nn块区域的路程和。
现已知调查兵团的物资总量为mm,请问最多能派遣多少支小分队参与调查?
思路:对于树来说,遍历所有点回到出发点每条边要经过两边,花费是所有边的权值和乘以二假设为sum。然后小分队从某一点出发到达某个目的点,两点之间最短路上的边只需要经过一次,所以花费就是sum减去最短路上边的权值,为使花费最少,就需要找到距离该点最远的点也就是树的直径的某个端点。那么做法就出来了,找到树的直径的端点(先从1搜一遍找到最远的端点,再从该点搜一遍找到最远的端点,这两个端点的最短路就是直径),然后枚举所有点,求出每一点的最小花费存入数组,再sort一遍,找到最小的那几个花费,就是答案了。
代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct Node{
int v;
long long w;
Node(int vv,long long ww):v(vv),w(ww){}
};
int n;
long long m;
vector<Node>edge[100005];
long long dist[2][100005];
void dfs(int u,int id,int pre,long long dis)
{
dist[id][u]=dis;
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i].v;
if(v==pre)continue;
dfs(v,id,u,dis+edge[u][i].w);
}
}
int main()
{
scanf("%d%lld",&n,&m);
long long sum=0;
for(int i=0;i<n-1;i++){
int u,v;
long long w;
scanf("%d%d%lld",&u,&v,&w);
edge[u].push_back(Node(v,w));
edge[v].push_back(Node(u,w));
sum+=w;
}
sum*=2;
int l,r;
long long temp=-1;
dist[0][1]=0;
dfs(1,0,0,0);
for(int i=1;i<=n;i++)if(dist[0][i]>temp)temp=dist[0][i],l=i;
dist[0][l]=0,temp=-1;
dfs(l,0,0,0);
for(int i=1;i<=n;i++)if(dist[0][i]>temp)temp=dist[0][i],r=i;
dist[1][r]=0;
dfs(r,1,0,0);
int i;
long long t=0,a[100005];
for(i=1;i<=n;i++){
a[i]=sum-max(dist[0][i],dist[1][i]);
//printf("%lld\n",a[i]);
}
sort(a+1,a+n+1);
for(i=1;i<=n;i++)
{
t+=a[i];
if(t>m)break;
}
printf("%d\n",i-1);
return 0;
}



京公网安备 11010502036488号