zoukankan      html  css  js  c++  java
  • 洛谷P2015 二叉苹果树(树状dp)

    题目描述

    有一棵苹果树,如果树枝有分叉,一定是分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个。

    输出格式:

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

    输入输出样例

    输入样例:
    5 2
    1 3 1
    1 4 10
    2 3 20
    3 5 20
    
    输出样例:
    21

    对于树状dp,就是在树上面做动态规划。关键点是树的层次性,而层次性又是有递归的建树而实现的。要注意这题是有根树,根节点给定是1,而且必须保留!
    题解写到注释里面了
    代码如下:
     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 #define inf 0x3f3f3f3f
     5 #define M 5000
     6 int next[M],pre[M],last[M],apple[M],dp[M][M],n,m,tot=0;
     7 /*
     8 dp[i][j]表示节点i保留j个枝条的所剩苹果最大值
     9 apple[i]表示第i条边上的苹果数
    10 next,pre,last是用来建边的数组
    11 tot来统计边的序号
    12 */
    13 void cnct (int u,int v,int w)
    14 {
    15     tot++;
    16     next[tot]=v;
    17     pre[tot]=last[u];
    18     last[u]=tot;
    19     apple[tot]=w;
    20 }
    21 int dfs (int u,int father)
    22 {
    23     int ans=0;//ans表示u节点的子节点数目
    24     for (int i=last[u];i!=0;i=pre[i])
    25     {
    26         int v=next[i],value=apple[i];
    27         if(v == father)continue;//如果下一个相邻节点就是父节点,则证明到底层了,开始递归父节点的兄弟节点
    28         ans+=dfs(v,u)+1;//递归到最上层的根节点1
    29         for(int j=min(ans,m);j>=1;--j)//因为有限制枝条的数目,取个min
    30         {
    31             for(int k=min(j,ans);k>=1;--k)
    32             dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k-1]+value);
    33 /*
    34 对于u节点下的子节点j,对j保留多少枝条最优进行dp
    35 在这里好好说明下,因为建树是我们是按照递归建的树。
    36 进行比较时,dp[u][j]都是前面选择除i外的子节点得到的最优解结果
    37 所以dp的时候不可能重复或者漏掉某节点
    38 */
    39         }
    40     }
    41     return ans;
    42 }
    43 int main()
    44 {
    45     //freopen("de.txt","r",stdin);
    46     memset(last,0,sizeof last);
    47     memset(next,0,sizeof next);
    48     memset(pre,0,sizeof pre);
    49     memset(dp,0,sizeof dp);
    50     scanf("%d%d",&n,&m);
    51     for(int i=1;i<n;++i)
    52     {
    53         int x,y,value;
    54         scanf("%d%d%d",&x,&y,&value);
    55         cnct(x,y,value);
    56         cnct(y,x,value);
    57     }
    58     dfs(1,0);
    59     printf("%d
    ",dp[1][m]);
    60     return 0;
    61 }
    62                        

  • 相关阅读:
    对MVC模型的自悟,详尽解释,为了更多非计算机人员可以理解
    openSUSE leap 42.3 实现有线 无线同时用
    Fedora27 源配置
    Ubuntu16.04添加HP Laserjet Pro M128fn打印机和驱动
    openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动
    OpenSUSE Leap 42.3下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    OpenSUSE Leap 42.3 安装java(Oracle jre)
    linux下支持托盘的邮件客户端Sylpheed
    Ubuntu下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    Firefox 浏览器添加Linux jre插件
  • 原文地址:https://www.cnblogs.com/agenthtb/p/5858703.html
Copyright © 2011-2022 走看看