• poj1947 Rebuilding Roads


    本题是给定一棵树(n, n - 1),试问最少去掉多少条边能够得到一个节点数恰为m(1≤ m ≤ n)的子树(连通块)。

    这是一道动态规划题,也就是说最终的最优解(答案)需要靠子问题的状态转移来合成。

    考虑一颗根节点为u的树(T),u的子节点集合为 V = { v1, ...,vk }。

    我们试着推导通过对T进行删边操作得到一颗节点数为i的子树T1所删的边的最小数目dp[u][i],其中u ∈ T1。

    则有:

    ①若T1 ∩ T(v1) ≠ ∅,则dp[u][i] = min{ dp[v1][j] + dp[u][i - j] }, 0 ≤ j ≤ i。

    ②若 T1 ∩ T(v1) = ∅, 则 dp[u][i] = 1 + dp[u][i]。

    实际上在递归过程中相当于把各个子树当成物品求价值后用背包的方式更新父节点的最优值。

    http://poj.org/problem?id=1947

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int maxn = 150 + 10;
     6 const int inf = 0x3f3f3f3f;
     7 int dp[maxn][maxn];
     8 int n, m, N;
     9 int cnt[maxn];
    10 struct Edge{
    11     int to, next;
    12 }edge[maxn];
    13 int root;
    14 int head[maxn];
    15 
    16 void addEdge(int u, int v){
    17     edge[N].next = head[u];
    18     edge[N].to = v;
    19     head[u] = N++;
    20 }
    21 
    22 void dfs(int u){
    23     //assume that T(u) is an isolated tree
    24     dp[u][1] = 0;
    25     for(int i = head[u]; i + 1; i = edge[i].next){
    26         int v = edge[i].to;
    27         dfs(v);
    28         for(int j = m; j >= 1; j--){
    29             int tem = dp[u][j] + 1;
    30             for(int k = 1; k < j; k++){//spilt j
    31                 tem = min(tem, dp[u][k] + dp[v][j - k]);
    32             }
    33             dp[u][j] = tem;
    34         }
    35     }
    36 }
    37 
    38 int main(){
    39     while(~scanf("%d%d", &n, &m)){
    40         N = 0;
    41         memset(head, -1, sizeof head);
    42         memset(cnt, 0, sizeof cnt);
    43         for(int i = 1, x, y; i < n; i++){
    44             scanf("%d%d", &x, &y);
    45             ++cnt[y];
    46             addEdge(x, y);
    47         }
    48         for(int i = 1; i <= n; i++){
    49             if(!cnt[i]){
    50                 root = i;
    51                 break;
    52             }
    53         }
    54         memset(dp, inf, sizeof dp);
    55         dfs(root);
    56         int ans = dp[root][m];
    57         for(int i = 1; i <= n; i++) ans = min(ans, dp[i][m] + 1);
    58         printf("%d
    ", ans);
    59     }
    60     return 0;
    61 }
    View Code
  • 相关阅读:
    安装CentOS7
    gitlab的CI/CD实现
    如何实现7*24小时灵活发布?阿里技术团队这么做
    架构整洁之道, 看这一篇就够了!
    什么是数据湖?有什么用?
    2020 云原生 7 大趋势预测
    饿了么交易系统 5 年演化史
    ajax 传参数 数组 会加上中括号
    文件下载
    数组常用方法
  • 原文地址:https://www.cnblogs.com/astoninfer/p/4872490.html
Copyright © 2020-2023  润新知