zoukankan      html  css  js  c++  java
  • 刷题总结——二叉苹果树(ssoj树形dp+记忆化搜索)

    题目:

    题目背景

    URAL:http://acm.timus.ru/problem.aspx?space=1&num=1018

    题目描述

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

    输出

    21

    题解:

      dp[i][j]:表示i号点所在子树(包括自己)共保留j个点可以留下的最多苹果

      注意这道题我把保留m条边变成保留m+1个点来求的·····

      另外注意在进行树形dp  dfs的时候用记忆化搜索·····

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=105;
    int first[N],next[N*2],go[N*2],val[N*2],tot;
    int n,m;
    int dp[N][N];
    inline void comb(int a,int b,int c)
    {
      next[++tot]=first[a],first[a]=tot,go[tot]=b,val[tot]=c;
      next[++tot]=first[b],first[b]=tot,go[tot]=a,val[tot]=c; 
    }
    inline void dfs(int u,int fa,int Val,int k)
    {
      if(u==0||k==0)  
      {
        dp[u][k]=0;
        return;
      }
      if(dp[u][k]!=-1)
        return;
      dp[u][k]=0;
      for(int i=0;i<k;i++)
      { 
        int l=0,r=0,vl,vr;
        for(int e=first[u];e;e=next[e])
        {
          int v=go[e];
          if(v==fa)  continue;   
          if(l==0) 
            l=v,vl=val[e];
          else 
          {  
            r=v,vr=val[e];
            break;
          }
        }
        dfs(l,u,vl,i);
        dfs(r,u,vr,k-i-1);
        dp[u][k]=max(dp[l][i]+dp[r][k-i-1]+Val,dp[u][k]);
      }
      return;
    }
    int main()
    {
      freopen("a.in","r",stdin);
      scanf("%d%d",&n,&m);
      m++;
      memset(dp,-1,sizeof(dp));
      int a,b,c;
      for(int i=1;i<n;i++)
      {
        scanf("%d%d%d",&a,&b,&c);
        comb(a,b,c);
      }
      dfs(1,0,0,m);
      cout<<dp[1][m]<<endl;
      return 0;
    }
  • 相关阅读:
    小知识点随手记
    [学习笔记]行列式
    集群心跳机制
    [学习笔记]整数划分数
    如何修改集群的公网信息(包括 VIP) (文档 ID 1674442.1)
    [学习笔记]二叉树的遍历
    Oracle RAC/Clusterware 多种心跳heartbeat机制介绍 RAC超时机制分析
    bzoj4671: 异或图——斯特林反演
    为Oracle Clusterware修改公用及私有网络接口
    [学习笔记]斯特林反演
  • 原文地址:https://www.cnblogs.com/AseanA/p/7400399.html
Copyright © 2011-2022 走看看