重建道路

题目描述

一场可怕的地震后,人们用 重建道路_子树 个牲口棚(编号 重建道路_子树_02)重建了农夫 John 的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。

John 想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有 重建道路_i++_03 个牲口棚的子树和剩余的牲口棚分离,John 想知道这些道路的最小数目。

输入格式

第一行两个整数,重建道路_子树重建道路_i++_03

第二行到第 重建道路_#include_06 行,每行两个整数 重建道路_子树_07重建道路_i++_08,表示节点 重建道路_子树_07 是节点 重建道路_i++_08 的父节点。牧场运输系统可以被构建成一棵以 1 号节点为根的树

输出格式

单独一行,包含一旦被破坏将分离出恰含 重建道路_i++_03 个节点的子树的道路的最小数目。

样例 #1

样例输入 #1

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

样例输出 #1

2

提示

样例解释

如果道路 重建道路_i++_12重建道路_#include_13 被破坏,含有节点(重建道路_子树_14)的子树将被分离出来。

限制与约定

重建道路_子树_15重建道路_#include_16,保证给出的是一棵树。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=201;
struct Edge{
    int to,next;
}e[N*2];
int du[N],a[N],dp[N][N];
int n,k,res=INF,EdgeCnt=0;
void addedge(int u,int v){
    int p=++EdgeCnt;
    e[p].to=v;e[p].next=a[u];
    a[u]=p;
}
void dfs(int u,int fa){
    dp[u][1]=du[u];
    for (int p=a[u];p;p=e[p].next){
        int v=e[p].to;
        if (v!=fa){
            dfs(v,u);
            for (int j=k;j>=1;j--)
                for (int k=1;k<=j;k++)
                    dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]-2);
        }
    }
    res=min(res,dp[u][k]);
}
int main(){
    scanf("%d%d",&n,&k);
    memset(dp,0x3f,sizeof(dp));
    for (int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
        du[u]++;du[v]++;
    }
    dfs(1,0);
    printf("%d",res);
    return 0;
}

 10