题目大意:给定一棵n个点的树,将叶子节点分为数个集合,使集合里点对最长距离不超过k,求最少集合数。
贪心,考虑一个非叶节点,它的下面的叶子结点对当前点之间的距离排序之后,当这个叶子结点和比它小的一个的和大于k的
时候,代表后面的每一个叶子结点都要新开一个集合,而之前的可以继续作为一个集合向上更新。最终会剩下一个集合,所以
答案要+1。注意要选择一个度数不为1的点作为开始点(就是非叶节点)。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
int n,k;
struct node
{
int to;
int nxt;
}edge[2000006];
int cnt=1,head[1000006];
int du[1000006],dis[1000006];
void init()
{
memset(head,-1,sizeof(head));
}
void add(int from,int to)
{
edge[cnt].to=to;
edge[cnt].nxt=head[from];
head[from]=cnt++;
}
int ans;
vector<int>vvc[1000006];
void dfs(int u,int fa)
{
if(du[u]==1)
{
dis[u]=1;
return;
}
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fa)continue;
dfs(to,u);
vvc[u].push_back(dis[to]);
}
sort(vvc[u].begin(),vvc[u].end());
int l=vvc[u].size();
int w,nww=vvc[u][0];
for(w=1;w<l;w++)
{
if(nww+vvc[u][w]>k)break;
nww=vvc[u][w];
}
ans+=l-w;dis[u]=nww+1;
}
int main()
{
scanf("%d%d",&n,&k);
init();
for(int i=1;i<=n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);add(b,a);
du[a]++;du[b]++;
}
for(int i=1;i<=n;i++)
{
if(du[i]>1)
{
dfs(i,i);break;
}
}
printf("%d",ans+1);
return 0;
}