#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f3f;
#define N 200
int dp[N][N], vis[N], p;
vector<int>vet[N];
void dfs(int x)
{
int si = vet[x].size();
for (int k = 0; k < si; k++)
{
int v = vet[x][k];
dfs(v);
for (int i = p; i > 1; i--)
{
for (int j = 1; j < i; j++)
{
dp[x][i] = min(dp[x][i], dp[x][i - j] + dp[v][j] - 2);
//为什么减2,一条是连上son与他的父亲,一条是连上父亲与儿子,因为这两个点之前都各算了一次
}
}
}
}
int main()
{
int n;
scanf("%d%d", &n, &p);
int u, v;
for (int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
vet[u].push_back(v);
vis[v] = 1;
}
int root;
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
root = i;
break;
}
}
for (int i = 1; i <= n; i++)
{
dp[i][1] = vet[i].size() + 1;//大家都加上一个父亲,给根加上虚拟的父亲。。
for (int j = 2; j <= p; j++)
{
dp[i][j] = inf;
}
}
dfs(root);
dp[root][p]--;//减去虚拟的
int ans = inf;
for (int i = 1; i <= n; i++)
{
ans = min(ans, dp[i][p]);
}
cout << ans << endl;
return 0;
}
第二种应该好理解点。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f3f;
#define N 200
int dp[N][N], vis[N], p;
vector<int>vet[N];
void dfs(int x)
{
int si = vet[x].size();
for (int k = 0; k < si; k++)
{
int v = vet[x][k];
dfs(v);
for (int i = p; i > 1; i--)
{
for (int j = 1; j < i; j++)
{
dp[x][i] = min(dp[x][i], dp[x][i - j] + dp[v][j] - 1);
//父亲与儿子切断的边连上。
}
}
}
}
int main()
{
int n;
scanf("%d%d", &n, &p);
int u, v;
for (int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
vet[u].push_back(v);
vis[v] = 1;
}
int root;
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
root = i;
break;
}
}
for (int i = 1; i <= n; i++)
{
dp[i][1] = vet[i].size();//只算到儿子的边。
for (int j = 2; j <= p; j++)
{
dp[i][j] = inf;
}
}
dfs(root);
int ans = dp[root][p];//除了根之外,其他还要切断他与父亲的边,所以其他加上1
for (int i = 1; i <= n; i++)
{
ans = min(ans, dp[i][p] + 1);
}
cout << ans << endl;
return 0;
}