dp[i][j]为第i个节点为根的子树具有j个节点最少要切的边数
subtree
对于 root 这个根节点来说, 要么选择 他的一个 儿子 k, 要么不选择。 如果选择 dp[root][j] = min( dp[k][i] + dp[root][j - i] ), k为root的子节点, 其中 0 < i < j; 如果不选择的话,就去掉root 和 k之间连线,dp[root][j] = dp[root] [j] + 1;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e2;
int n,m,dp[N][N],vis[N],x,y,root;
vector<int> a[N];
void dfs(int x)
{
for(int i=0;i<=m;i++)
dp[x][i]=inf;
dp[x][1]=0;
for(int i=0;i<a[x].size();i++)
{
int y=a[x][i];
dfs(y);
for(int j=m;j>=1;j--)//m个体积 01背包
{
int t=dp[x][j]+1;//不选择
for(int k=1;k<j;k++)
{
t=min(t,dp[y][k]+dp[x][j-k]);//选择
}
dp[x][j]=t;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
while(cin >>n >> m)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=0;i<n-1;i++)
{
cin >> x >> y;
a[x].push_back(y);
vis[y]=1;
}
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
root=i;
break;
}
}
dfs(root);
int res=dp[root][m];//以root为根
for(int i=1;i<=n;i++)
res=min(res,dp[i][m]+1);//不以root为根
cout << res << endl;
}
return 0;
}