本文共 2767 字,大约阅读时间需要 9 分钟。
给 一 颗 树 , 问 最 少 删 除 几 条 边 , 可 以 使 一 颗 子 树 含 有 p 个 节 点 ? 给一颗树,问最少删除几条边,可以使一颗子树含有p个节点? 给一颗树,问最少删除几条边,可以使一颗子树含有p个节点?
树 上 问 题 , 想 必 是 树 形 d p 。 树上问题,想必是树形dp。 树上问题,想必是树形dp。
设 f [ i ] [ j ] 表 示 以 i 为 根 的 子 树 , 有 j 个 节 点 最 小 删 除 边 数 。 设f[i][j]表示以i为根的子树,有j个节点最小删除边数。 设f[i][j]表示以i为根的子树,有j个节点最小删除边数。
状 态 转 移 : 状态转移: 状态转移:
f [ u ] [ j ] = m i n ( f [ u ] [ j ] , f [ u ] [ j − k ] + f [ v ] [ k ] − 1 ) f[u][j] = min(f[u][j], f[u][j-k]+f[v][k]-1) f[u][j]=min(f[u][j],f[u][j−k]+f[v][k]−1)为 什 么 要 减 1 ? 为什么要减1? 为什么要减1?
f [ i ] [ j ] 都 是 包 含 根 节 点 , f [ u ] [ j − k ] + f [ v ] [ k ] 中 间 会 多 出 一 条 u 和 v 相 连 的 边 。 f[i][j]都是包含根节点,f[u][j-k]+f[v][k]中间会多出一条u和v相连的边。 f[i][j]都是包含根节点,f[u][j−k]+f[v][k]中间会多出一条u和v相连的边。最 后 答 案 是 什 么 ? 最后答案是什么? 最后答案是什么?
int ans = f[1][p]; for(int i = 2;i <= n; i++) { if(f[i][p] < ans) ans = f[i][p] + 1; }
为 什 么 除 了 根 节 点 1 , 其 他 都 要 + 1 ? 为什么除了根节点1,其他都要+1? 为什么除了根节点1,其他都要+1?
假 设 p = 4 的 话 , 可 以 看 见 保 留 以 2 为 根 节 点 是 明 智 的 选 择 。 假设p=4的话,可以看见保留以2为根节点是明智的选择。 假设p=4的话,可以看见保留以2为根节点是明智的选择。但 是 d p 后 f [ 2 ] [ 4 ] = 0 , 为 什 么 呢 ? 因 为 不 需 要 删 除 任 何 边 , 但 是 1 − 2 需 要 删 除 , 所 以 + 1 。 但是dp后f[2][4]=0,为什么呢?因为不需要删除任何边,但是1-2需要删除,所以+1。 但是dp后f[2][4]=0,为什么呢?因为不需要删除任何边,但是1−2需要删除,所以+1。
总 流 程 : 总流程: 总流程:
for(int i = 1;i <= n; i++) f[i][1] = a[i];
int dfs(int u) { int sum = 1; for(auto v : g[u]) { int temp = dfs(v); sum += temp; // 背包。。。 } return sum;}
for(int j = sum;j >= 1; j--) { for(int k = 1;k < j; k++) { f[u][j] = min(f[u][j], f[u][i - k] + f[v][k] - 1); }}
#include "bits/stdc++.h"using namespace std;const ll INF = 0x3f3f3f3f;const int N = 1e3 + 10;vector> f(N, vector (N, INF));vector g[N];int dfs(int u) { int sum = 1; for(auto v : g[u]) { int temp = dfs(v); sum += temp; for(int j = sum;j >= 1; j--) { for(int k = 1;k < j; k++) { f[u][j] = min(f[u][j], f[u][j - k] + f[v][k] - 1); } } } return sum;}void solve() { int n, p; cin >> n >> p; vector a(n + 1); for(int i = 1;i <= n - 1; i++) { int u, v; cin >> u >> v; a[u]++; g[u].eb(v); } for(int i = 1;i <= n; i++) f[i][1] = a[i]; dfs(1); int ans = f[1][p]; for(int i = 2;i <= n; i++) { if(f[i][p] < ans) ans = f[i][p] + 1; } cout << ans << endl;}signed main() { solve();}
转载地址:http://vfjwz.baihongyu.com/