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

    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


    树上的背包问题,很容易就想到如果删除一个子节点,那么以这个节点的棵子树就会全部删除,那么对这个子树删除的节点就不能超过子节点个数。
    所以我们先dfs一边,求出有多少一个节点有多少子节点,并标记处father,保证不会到father
    f[i][j]<在i这个子树中删除j个边的最大值,然后贪心维护最大就好了
    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #define ll long long 
    using namespace std;
    const int maxn=150;
    int read(){
        int an=0,f=1;char ch=getchar();
        while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
        while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
        return f*an;
    }
    int f[maxn],dp[maxn][maxn],cnt,fa[maxn],son[maxn],Q,n;
    bool vis[maxn],vis2[maxn];
    struct saber{
    int to,nex,wi;
    }b[maxn<<1];
    void add(int x,int y,int z){
        cnt++;
        b[cnt].nex=f[x];
        b[cnt].to=y;
        f[x]=cnt;
        b[cnt].wi=z;
    }
    void dfs(int x){
        vis[x]=1;son[x]=1;
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
            if(!vis[v]){
                dfs(v);
                fa[v]=x;
                son[x]+=son[v];
            }
        }
    }
    void DP(int x){
        vis2[x]=1;
        for(int i=f[x];i;i=b[i].nex){
            int v=b[i].to;
            if(fa[x]!=v){
                DP(v);
                for(int j=min(son[x],Q);j>0;j--)
                    for(int k=min(j,Q);k>0;k--)
                    dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k-1]+b[i].wi);
            }
        }
    }
    int main(){
        n=read();Q=read();
        for(int i=1;i<n;i++){
            int x=read(),y=read(),z=read();
            add(x,y,z);
            add(y,x,z);
        }
        dfs(1);
        DP(1);
        cout<<dp[1][Q];
        return 0;
    }
    apple_tree

    by:s_a_b_e_r


    楼上一直坚持两遍dfs,其实一遍就好了啊qwq

    而且既然只向下dp,存单向边就可以啦(但是要存一下father)

    因为是二叉树所以非常好办

    如果点x的子树一共要保留i根树枝

    肯定是一部分(j)分给左子树,剩下的(i-j)给右子树

    于是就可以愉快地填表DP了^_^

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=109;
    int n,q,p[N],fa[N],f[N][N],cnt,son[N];
    struct edge{
    int to,nex,val;
    }e[N<<1];
    void add(int u,int v,int w)
    {
         ++cnt;
         e[cnt].to=v;
         e[cnt].nex=p[u];
         p[u]=cnt;
         e[cnt].val=w;
    }
    void dfs(int u)
    {
         son[u]=1;
         for(int i=p[u];i;i=e[i].nex)
         {
           int v=e[i].to;
           dfs(v);
           son[u]+=son[v];
           for(int j=min(q,son[u]);j>=1;--j)
           for(int k=min(j,son[u]);k>=1;--k)
           f[u][j]=max(f[u][j],f[u][j-k]+f[v][k-1]+e[i].val);
         }
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;++i)
        {
          int x,y,z;
          scanf("%d%d%d",&x,&y,&z);
          if(fa[y]){fa[x]=y;add(y,x,z);}
          else {fa[y]=x;add(x,y,z);}
        }
        dfs(1);
        cout<<f[1][q]<<endl;
        return 0;
    }
    apple apple tree

    by:wypx


    s:I have an apple……

    w:I have an another apple……apple tree!!!

  • 相关阅读:
    三、Oracle 查询+where条件
    二、Oracle 数据库基本操作
    一、Oracle 安装
    18.JAVA经典编程题(50题及答案)
    17.网络编程
    16.xml
    Js模块化开发--seajs和gruntJs
    git命令行指南
    nodejs学习笔记---1
    面向对象及组件开发---笔记1
  • 原文地址:https://www.cnblogs.com/ck666/p/7517654.html
Copyright © 2011-2022 走看看