zoukankan      html  css  js  c++  java
  • [Luogu] P2015 二叉苹果树

    [Luogu] P2015 二叉苹果树


    1.题目

    题目描述

    有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
    这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
    我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

    2   5
     / 
     3   4
       /
       1
    

    现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
    给定需要保留的树枝数量,求出最多能留住多少苹果。

    输入输出格式

    输入格式:

    第1行2个数,N和Q(1<=Q<= N,1<N<=100)。
    N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。
    每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。
    每根树枝上的苹果不超过30000个。

    输出格式:

    一个数,最多能留住的苹果的数量。

    输入输出样例

    输入样例#1:

    5 2
    1 3 1
    1 4 10
    2 3 20
    3 5 20
    

    输出样例#1:

    21
    

    2.题解

    树形DP。

    dfs,然后对各节点边统计子树边DP。

    (f[i][j])为当前为第(i)个点,在其子树上选择了(j)条边后的最大边权和,(size[i])为以(i)为根节点的子树上的边数。对当前点跑一个背包。

    转移方程为(f[i][j] = max(f[i][j], f[i][j - k - 1] + f[v][k] + w)),其中(1 leqslant j leqslant min(size[i], m))(v in i's~subtree)(0 leqslant k leqslant min(j - 1, size[v]))(w)为当前连接(i)(v)的边权。

    (j, v)的取值都比较好理解,(k geqslant 0)的原因是可以只选当前边,不考虑子树。(leqslant j - 1)的原因是需要为当前边预留位置。

    #include <cstdio>
    const int MAXN = 110;
    struct EDGE{
        int to, next, wgh;
    }edge[MAXN << 1];
    int n, m, top, u, v, w;
    int f[MAXN][MAXN], size[MAXN], head[MAXN];
    template <class T>
    inline T min(T a, T b) {return (a < b ? a : b);}
    template <class T>
    inline T max(T a, T b) {return (a > b ? a : b);}
    inline void add_edge(int u, int v, int w) {
        edge[++top].to = v;
        edge[top].wgh = w;
        edge[top].next = head[u];
        head[u] = top;
    
        edge[++top].to = u;
        edge[top].wgh = w;
        edge[top].next = head[v];
        head[v] = top;
        
        return ;
    }
    inline void dfs(int now, int fa) {
        int tmp(0), tmw(0);
        for (int i = head[now]; i; i = edge[i].next)
            if((tmp = edge[i].to) != fa) {
                dfs(tmp, now); size[now] += size[tmp] + 1;
                tmw = edge[i].wgh;
                for (int j = min(size[now], m); j >= 1; --j)
                    for (int k = min(j - 1, size[tmp]); ~k; --k)
                        f[now][j] = max(f[now][j], f[now][j - k - 1] + f[tmp][k] + tmw);
            }
        return ;
    }
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i < n; ++i)
            scanf("%d%d%d", &u, &v, &w), add_edge(u, v, w);
        dfs(1, 1);
        printf("%d
    ", f[1][m]);
        return 0;
    }
    
  • 相关阅读:
    Alpha冲刺第一天
    团队项目-需求分析
    设计模式第二次作业
    设计模式第一次作业
    冲刺合集
    冲刺NO.12
    项目测试
    冲刺NO.11
    冲刺NO.9
    冲刺NO.10
  • 原文地址:https://www.cnblogs.com/manziqi/p/9796251.html
Copyright © 2011-2022 走看看