AGC001 Shorten Diameter

版权声明:本文为博主原创文章,不管你喜不喜欢都请在注明作者后转载~( ̄▽ ̄~) https://blog.csdn.net/C20190102/article/details/82943999

题目

传送门

题目大意

我们称一个直径不超过 K K 的数为好树,给定一个 N ( N 2000 ) N(N\leq 2000) 个结点的无根树,至少需要删除多少个点,它才能变成一个好树?

思路

根据树的直径的性质:

  • K K 是偶数,枚举一个点作为好树的中心,那么这个点到任何一个点的距离都应小于等于 K 2 \dfrac{K}{2} ,需要删掉的点就是到它距离超过这么多的点。
  • K K 是奇数,枚举一条边 ( u , v ) (u,v) 作为好树的中心边,那么任何一个点到 u u 或到 v v 的距离都应小于等于 K 1 2 \dfrac{K-1}{2} ,请自行脑补画面。

时间复杂度 O ( N 2 ) O(N^2)

代码

#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);
}

猜你喜欢

转载自blog.csdn.net/C20190102/article/details/82943999
今日推荐