zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    UVA10090 数论基础 exgcd
    UVA 10037 贪心算法
    ST表入门学习poj3264 hdu5443 hdu5289 codeforces round #361 div2D
    poj3254状压DP入门
    I.点进来吧,这里有你想要的(01背包)
    J.哭泣的阿木木(线段树模板题)
    可怜的ljb(树状数组,逆序对)
    D武器大师的宝贝(最大相交区间,异或,最大公约数)
    银行排队模拟(队列,模拟,数据结构)
    B
  • 原文地址:https://www.cnblogs.com/Liuz8848/p/10684916.html
Copyright © 2011-2022 走看看