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

    题目描述

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

    Solution:

      本题树形$dp$板子(不过我调了好几遍啊`~`)。

      题意要留下$q$个树枝,等同于在原树上选$q$根树枝,使得树枝必须和父节点相连,且价值最大。

      那么直接套上分组背包板子,定义状态$f[i][j]$表示在$i$的子树中选$j$条边的最大价值,则不难想到状态转移方程:$f[u][j]=max(f[u][j],f[u][j-k]+f[v][k-1]+w[u,v])$(范围$jleq sizeu,;kleq min(j,sizev)$,特别注意转移时是$f[v][k-1]$(被这坑了几遍),因为在$v$子树中选边,就必须保证连通先选上$w[u,v]$这条边,所以在$v$子树中只能选$k-1$条边

      最后输出目标状态$f[n][q]$就好了。  

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)>(b)?(b):(a))
    
    using namespace std;
    const int N=205;
    
    int n,m,rd[N],to[N],net[N],w[N],f[N][N],cnt,h[N];
    
    il void add(int u,int v,int c){
        rd[v]++,to[++cnt]=v,net[cnt]=h[u],h[u]=cnt,w[cnt]=c;
    }
    
    il int dfs(int u,int fa){
        if(rd[u]==1&&u!=1) return 1;
        int tot=0,sizev;
        for(int i=h[u];i;i=net[i])
            if(to[i]!=fa){
                sizev=dfs(to[i],u);
                tot+=sizev;
                Bor(j,1,tot) {
                    int c=Min(sizev,j);
                    For(k,1,c) f[u][j]=Max(f[u][j-k]+f[to[i]][k-1]+w[i],f[u][j]);
                }
            }
        return tot+1;
    }
    
    int main(){
        ios::sync_with_stdio(0);
        cin>>n>>m;
        int u,v,c;
        For(i,1,n-1){
            cin>>u>>v>>c;
            add(u,v,c),add(v,u,c);
        }
        dfs(1,1);
        cout<<f[1][m];
        return 0;
    }
  • 相关阅读:
    datalist和repeater中radiobutton单选的问题
    SQL循环在表中增加新列
    [jQuery]使用jQuery.Validate进行客户端验证(高级篇上)——不使用微软验证控件的理由
    C# Excel 行高,列宽,合并单元格,单元格边框线,冻结 关于C#操作EXCLE常见操作比较全的
    JS弹出窗口的运用与技巧(转)
    设计模式完整备忘录
    jquery + ashx + Json 操作数据
    SQL STUFF函数 拼接字符串
    获取SQL 各字段说明,表名等有效信息
    谈谈对于企业级系统架构的理解
  • 原文地址:https://www.cnblogs.com/five20/p/9166513.html
Copyright © 2011-2022 走看看