P1272 重建道路

题目描述

一场可怕的地震后,人们用 NN 个牲口棚(编号 1N1\sim N)重建了农夫 John 的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是唯一的。因此,牧场运输系统可以被构建成一棵树。

John 想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有 PP 个牲口棚的子树和剩余的牲口棚分离,John 想知道这些道路的最小数目。

输入格式

第一行两个整数,NNPP

第二行到第 nn 行,每行两个整数 IIJJ,表示节点 II 是节点 JJ 的父节点。牧场运输系统可以被构建成一棵以 1 号节点为根的树。

输出格式

单独一行,包含一旦被破坏将分离出恰含 PP 个节点的子树的道路的最小数目。

输入输出样例 #1

输入 #1

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

输出 #1

2

说明/提示

样例解释

如果道路 141-4151-5 被破坏,含有节点(1,2,3,6,7,81,2,3,6,7,8)的子树将被分离出来。

限制与约定

1N1501\le N\le 1501PN1\le P\le N,保证给出的是一棵树。

参考代码

by

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

typedef long long LL;

const LL Maxn = 150 + 5;
const LL Inf = 1e18;

vector<LL> grid[Maxn];
LL res = Inf;

LL dfs(LL u, LL p, vector<vector<LL> >& dp) {
    dp[u][1] = grid[u].size() + (u != 1);
    LL sum = 1;

    for (auto v : grid[u]) {
        sum += dfs(v, p, dp);
        for (LL i = min(sum, p); i > 1; --i) {
            for (LL j = 1; j <= i; ++j)
                dp[u][i] = min(dp[u][i], dp[u][i - j] + dp[v][j] - 2);
        }
    }

    res = min(res, dp[u][p]);

    return sum;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    LL n, p, u, v;
    cin >> n >> p;
    for (LL i = 1; i < n; ++i) {
        cin >> u >> v;
        grid[u].emplace_back(v);
    }

    vector<vector<LL> > dp(n + 1, vector<LL> (p + 1, Inf));
    dfs(1, p, dp);

    cout << res;

    return 0;
}

0 条评论

目前还没有评论...