刷题总结——二叉苹果树(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;
}
时间: 2024-10-05 11:42:55

刷题总结——二叉苹果树(ssoj树形dp+记忆化搜索)的相关文章

刷题总结——选课(ssoj树形dp+记忆化搜索+多叉树转二叉树)

题目: 题目描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了 N(N<300)门的选修课程,每个学生可选课程的数量 M 是给定的.学生选修了这M门课并考核通过就能获得相应的学分.在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如<Frontpage>必须在选修了<Windows操作基础>之后才能选修.我们称<Windows操作基础>是<Frontpage

【DP】树形DP 记忆化搜索

DP中的树形DP,解决方法往往是记忆化搜索.显然,树上递推是很困难的.当然做得时候还是得把状态定义和转移方程写出来:dp[u][1/0]表示以u为根节点的树 涂(1) 或 不涂(0) 颜色的最少方案数.树上DP有两个经典问法:一条边两端至少有个一个端点涂色,问整个tree最少涂色次数:还有一种忘了...此题是前种问法. #include<cstdio> #include<cstring> #include<algorithm> using namespace std;

11782 - Optimal Cut(树形DP+记忆化搜索)

题目链接:11782 - Optimal Cut 题意:按前序遍历给定一棵满二叉树,现在有k次,可以选k个节点,获得他们的权值,有两个条件: 1.一个节点被选了,他的子节点就不能选了. 2.最终选完后,根到所有叶子的路径上,都要有一个被选的节点. 思路:树形dp,dp[u][k]代表在结点u,可以选k个节点,那么就分两种情况 选u节点,dp[u][k] = node[u]; 选子节点之和,那么就把k次分配给左右孩子,dp[u][k] = max(dp[u][k], dp[u][i], dp[u]

[Luogu2015]二叉苹果树(树形dp)

[Luogu2015] 二叉苹果树 题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树 2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 输入输出格式 输入格式: 第1行2个数,N和Q(1<=Q<= N,1&l

二叉苹果树(树形DP)

题面 原题 Solution 显然我们考虑这道题目可以很蠢的写一个Dp对吧. 考虑\(dp_i,j\)表示以i为根,保留j个节点的最大苹果数. 然后就可以树形Dp的写了. #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> #include<iostream> #include<queue>

加分二叉树 vijos1991 NOIP2003第三题 区间DP/树形DP/记忆化搜索

描述 设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数.不考虑它的空子树. 试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的

二叉苹果树(树型DP+背包)

二叉苹果树 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点).这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树: 2   5 \  / 3  4 \  / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 程序名:apple 输入格式: 第1行2个数,N和Q(1<=Q<= N,1<N<=

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&amp;&amp;NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇 今天早上起床发现194了然后就各种刷--当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题--结果尼玛调了能有一个小时--我居然没看到编号最小这个限制0.0 首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减 于是我们记忆化搜索 首先用

九度OJ刷题——1009:二叉搜索树

题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束.接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树.接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树. 输出: 如果序列相同则输出YES,否则输出NO 样例输入: 2 567432 543267 576342 0 样例输出: YES NO 这题我的思