• 【P2015】二叉苹果树 (树形DP分组背包)


    题目描述

    有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

    这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

    现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

    给定需要保留的树枝数量,求出最多能留住多少苹果。

    输入输出格式

    输入格式:

    第1行2个数,N和Q(1<=Q<= N,1<N<=100)。

    N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

    每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

    每根树枝上的苹果不超过30000个。

    输出格式:

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

    Solution

    树形DP一道模板题,考虑DP

    DP[ i ][ j ]表示在以i为结点的子树中保留j个边能得到的最大苹果数量

    状态转移方程如下

             for(int j=min(num[cur],m);j;--j)
                  for(int k=min(num[ev],j-1);k>=0;--k)
                    DP[cur][j]=max(DP[cur][j],DP[cur][j-k-1]+DP[ev][k]+e[i].w);

    cur表示当前遍历到的节点,num[cur]表示以cur为节点的子树的边数(可以通过DFS预处理)

    j枚举当前节点子树的保留边的个数,k表示当前边的v节点的子树的保留的边的个数,DP[cur][j]可以由保留j-k-1条边的前提下保留一个子树的k个节点转移过来。

    那么问题来了,如果要正确转移我们需要在处理num数组的前提下从叶节点转移,并且枚举到每条边,如何做到呢

    考虑DFS的遍历顺序和树的结构是一样的,我们可以在回溯的过程中DP,这样就完美了

    Code

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define maxn 1505
    #define re register
    using namespace std;
    int DP[maxn][maxn<<2];
    int cnt,ans,n,x,num[maxn],y,z,head[maxn],m;
    bool vis[maxn];
    struct Edge{
        int v,w,nxt;
    }e[maxn<<2];
    void add(int u,int v,int w)
    {
        e[++cnt].v=v;
        e[cnt].w=w;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }
    int dfs(int cur)
    {
        for(int i=head[cur];i;i=e[i].nxt)
        {
            int ev=e[i].v;
            if(!vis[ev])
            {
                vis[ev]=1;
                num[cur]++;
                num[cur]+=dfs(ev);
                
                for(int j=min(num[cur],m);j;--j)
                  for(int k=min(num[ev],j-1);k>=0;--k)
                    DP[cur][j]=max(DP[cur][j],DP[cur][j-k-1]+DP[ev][k]+e[i].w);
            }
        }
        return num[cur];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(re int i=1;i<=n-1;++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        vis[1]=1;
        dfs(1);
        printf("%d
    ",DP[1][m]);
        return 0;
    }
  • 相关阅读:
    记一次网站迁移的过程
    如何才能搜索微信群和网盘群
    2021最新车载u盘歌曲集合,每轴更新。想要拉你入群
    工具分享:目录生成器
    福利,剪映PC版来了~ 支持windos系统和苹果系统
    微信8.0来了,可以加1w人好友,微商必看!!!
    centOS7安装 redis server
    Task handler raised error: ValueError('not enough values to unpack (expected 3, got 0)')
    《More Effective C++》读书笔记(下)
    《More Effective C++》读书笔记(中)
  • 原文地址:https://www.cnblogs.com/Liuz8848/p/10684916.html
Copyright © 2020-2023  润新知