洛谷 P1272 重建道路
url: https://www.luogu.com.cn/problem/P1272
tag:
动态规划,树形DP
思路:
简单的树形DP和背包结合。令 f[u][j]
表示以u节点为根的子树在需要取出j个节点时最少需要断的边。最后在输出答案的时候在所有节点中选择一个答案最小的,注意选择其他节点为根节点时需要断去父节点和其之间的一条边。最后输出答案即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200;
int h[N], e[N * 2], ne[N * 2], idx;
int s[N];
int n, p;
int f[N][N];
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
void dfs(int u, int fa)
{
s[u] = 1;
f[u][1] = 0;
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (v == fa) continue;
dfs(v, u);
s[u] += s[v];
for (int j = min(s[u], p); j >= 0; j --)
{
f[u][j] += 1;
for (int k = 0; k <= min(j, s[v]); k++)
f[u][j] = min(f[u][j], f[u][j - k] + f[v][k]);
}
}
}
int main()
{
memset(h, -1, sizeof h);
memset(f, 0x3f, sizeof f);
cin >> n >> p;
for (int i = 0; i < n - 1; i ++)
{
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1, 0);
int res = f[1][p];
for (int i = 2; i <= n; i ++) res = min(res, f[i][p] + 1);
cout << res << endl;
return 0;
}