[洛谷P2015] 二叉苹果树

题目描述

有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

2   5
 \ / 
  3   4
   \ /
    1

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入输出格式

输入格式:

 

第1行2个数,N和Q(1<=Q<= N,1

N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

 

输出格式:

 

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

 

输入输出样例

输入样例#1:

5 2
1 3 1
1 4 10
2 3 20
3 5 20

输出样例#1:

21

比较基础的树形dp,以每个节点及节点对应剪枝数为状态,容易得出方程

f\left ( u,i \right )=max\left \{ f\left ( v,j \right )+f\left ( u,i-j-1 \right )+w\left ( u,v \right ) \right \}

其中 u,v 表示当前节点及子节点,i j 表示当前状态还有多少枝条可剪

由于核心部分由递推实现,j 的更新顺序应该从大到小,防止覆盖

代码

#include
#include
#include
#include
using namespace std;
int n,q;
const int N=101;
int d[N][N];
struct edge
{
    int to; int w;
    edge(int v,int s):to(v),w(s){}
};
vector G[N];
void dp(int u,int fa)
{
    for(int i=0;i=0;i--)
            for(int j=0;j

 这是我第一次写的,很没有条理的搜索,un记录了每个节点位于限制状态下的剪枝状态,事实上没必要考虑限制,因为更新过程是从顶到底层层搜索,不会访问到不需要的部分

不过这还是有优点的,这是一次漂亮的状态压缩啊!(滑稽)

#include
#include
#include
#include
using namespace std;
int n,q,tot=0;
const int N=101;
int d[N][N];
struct edge
{
    int to; int w;
    edge(int v,int s):to(v),w(s){}
};
vector G[N];
int dp(int u,int fa,int un)
{
    int &ans=d[u][un];
    if(tot>=un) return ans=0;//边界
    if(ans) return ans;//记忆化
    edge x=edge(0,0); edge y=edge(0,0); 
    for(int i=0;i

衍生题目:选课

你可能感兴趣的:(dp,题解)