博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P1272 重建道路 树上背包
阅读量:400 次
发布时间:2019-03-05

本文共 2767 字,大约阅读时间需要 9 分钟。

P1272 重建道路 树上背包

传送门:

题意

给 一 颗 树 , 问 最 少 删 除 几 条 边 , 可 以 使 一 颗 子 树 含 有 p 个 节 点 ? 给一颗树,问最少删除几条边,可以使一颗子树含有p个节点? 使p

思路

树 上 问 题 , 想 必 是 树 形 d p 。 树上问题,想必是树形dp。 dp

设 f [ i ] [ j ] 表 示 以 i 为 根 的 子 树 , 有 j 个 节 点 最 小 删 除 边 数 。 设f[i][j]表示以i为根的子树,有j个节点最小删除边数。 f[i][j]ij

状 态 转 移 : 状态转移:

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][jk]+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][jk]+f[v][k]uv

最 后 答 案 是 什 么 ? 最后答案是什么?

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=42

但 是 d p 后 f [ 2 ] [ 4 ] = 0 , 为 什 么 呢 ? 因 为 不 需 要 删 除 任 何 边 , 但 是 1 − 2 需 要 删 除 , 所 以 + 1 。 但是dp后f[2][4]=0,为什么呢?因为不需要删除任何边,但是1-2需要删除,所以+1。 dpf[2][4]=012+1


总 流 程 : 总流程:

  1. 预 处 理 f [ i ] [ 1 ] = a [ i ] , a [ i ] 为 每 个 点 的 出 度 。 预处理f[i][1] = a[i],a[i]为每个点的出度。 f[i][1]=a[i]a[i]
for(int i = 1;i <= n; i++) f[i][1] = a[i];
  1. d f s ( 1 ) , 返 回 值 为 s u m , 表 示 以 u 为 子 树 的 节 点 个 数 , 然 后 就 可 以 转 化 成 背 包 了 。 dfs(1),返回值为sum,表示以u为子树的节点个数,然后就可以转化成背包了。 dfs(1)sumu
int dfs(int u) {
int sum = 1; for(auto v : g[u]) {
int temp = dfs(v); sum += temp; // 背包。。。 } return sum;}
  1. 状 态 转 移 。 状态转移。
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); }}

Code

#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/

你可能感兴趣的文章