题意
给出一个
n
n
n 个节点的树,每次操作可以删除一个叶子节点
问最少需要进行多少次操作,才能让剩下的树满足直径不超过
k
k
k
考虑对答案求补集,也就是考虑留下哪些节点。
对于一棵树的直径中点,满足所有点到中点的距离不超过直径的一半。注意当直径长度为奇数时,直径中点为一条边
那么,我们可以枚举每一个点(边)作为直径中点时,直径不超过
k
k
k 的树的最大节点数
时间复杂度 O ( n 2 ) \mathcal O(n^2) O(n2)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int Maxn=2010;
vector <int> e[Maxn];
int d[Maxn];
int n,k,ans,tot;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
inline void add(int x,int y)
{
e[x].push_back(y);
}
void dfs(int x,int fa)
{
d[x]=d[fa]+1;
if(d[x]<=(k>>1))++tot;
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i];
if(y==fa)continue;
dfs(y,x);
}
}
int main()
{
n=read(),k=read();
for(int i=1;i<n;++i)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
if(k & 1)
{
for(int x=1;x<=n;++x)
for(int i=0;i<e[x].size();++i)
{
int y=e[x][i];
if(x>y)continue;
tot=0;
d[y]=-1,dfs(x,y);
d[x]=-1,dfs(y,x);
ans=max(ans,tot);
}
}
else
{
d[0]=-1;
for(int i=1;i<=n;++i)
{
tot=0,dfs(i,0);
ans=max(ans,tot);
}
}
printf("%d\n",n-ans);
return 0;
}