POJ1947 - Rebuilding Roads - 树形dp

Rebuilding Roads

题目链接

分类dfs and similar trees dp

1.题意概述

  • 给你一颗有 n 个节点构成是树,现在要你删去最少的边,使得剩下连通的点构成的树刚好有p个节点。

2.解题思路

  • 容易想到是一个树形dp, dp[i][j] 表示以 i 节点为根节点,得到j个节点的子树需要去掉的最少边数,那么转移方程为:考虑其儿子 k 选或者不选——最后取个最小值就行
    • 如果不去掉k的子树: dp[s][i]=min(dp[s][j]+dp[k][ij]),0ji
    • 如果去掉 k 的子树:dp[s][i]=dp[s][i]+1

    3.AC代码

    #define N 152
    int f[N][N], sonA[N], sonB[N];
    bool pa[N];
    int n, p;
    void init() {
        memset(pa, 0, sizeof pa);
        memset(sonA, 0, sizeof sonA);
        memset(sonB, 0, sizeof sonB);
    }
    void dfs(int u) {
        fill(f[u], f[u] + p + 1, INF);
        f[u][1] = 0;
        int k = sonA[u];
        while (k) {
            dfs(k);
            per(i, 1, p + 1) {
                int tmp = f[u][i] + 1;
                rep(j, 1, i)
                    tmp = min(tmp, f[k][i - j] + f[u][j]);
                f[u][i] = tmp;
            }
            k = sonB[k];
        }
    //  rep(i, 1, p + 1) printf("%d ", f[u][i]);
    //  puts("");
    }
    int main() {
        while (~scanf("%d%d", &n, &p)) {
            init();
            rep(i, 1, n) {
                int u, v;
                scanf("%d%d", &u, &v);
                pa[v] = 1;
                sonB[v] = sonA[u];
                sonA[u] = v;
            }
            int sta = 0;
            rep(i, 1, n + 1)
            if (!pa[i]) {
                sta = i;
                break;
            }
            dfs(sta);
            int ans = f[sta][p];
            rep(i, 1, n + 1) {
                if (i != sta)
                    ans = min(ans, f[i][p] + 1);
            }
            printf("%d\n", ans);
        }
        return 0;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值