题目
题目大意
我们称一个直径不超过 K K K的数为好树,给定一个 N ( N ≤ 2000 ) N(N\leq 2000) N(N≤2000)个结点的无根树,至少需要删除多少个点,它才能变成一个好树?
思路
根据树的直径的性质:
- 若 K K K是偶数,枚举一个点作为好树的中心,那么这个点到任何一个点的距离都应小于等于 K 2 \dfrac{K}{2} 2K,需要删掉的点就是到它距离超过这么多的点。
- 若 K K K是奇数,枚举一条边 ( u , v ) (u,v) (u,v)作为好树的中心边,那么任何一个点到 u u u或到 v v v的距离都应小于等于 K − 1 2 \dfrac{K-1}{2} 2K−1,请自行脑补画面。
时间复杂度 O ( N 2 ) O(N^2) O(N2)。
代码
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 2000
struct Edge{
int v,u;
}E[MAXN+5];
int N,K;
vector<int> G[MAXN+5];
//有多少个点需要删掉
int dfs(int u,int f,int MaxD,int D){
int ret=0;
if(D>MaxD)
ret++;
for(int i=0;i<int(G[u].size());i++){
int v=G[u][i];
if(v!=f)
ret+=dfs(v,u,MaxD,D+1);
}
return ret;
}
int main(){
scanf("%d%d",&N,&K);
for(int i=1;i<N;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
E[i]=(Edge){u,v};
}
int Ans=N;
if(K&1)//两种情况
for(int i=1;i<N;i++)
Ans=min(Ans,dfs(E[i].u,E[i].v,K/2,0)+dfs(E[i].v,E[i].u,K/2,0));
else
for(int i=1;i<=N;i++)
Ans=min(Ans,dfs(i,-1,K/2,0));
printf("%d",Ans);
}