【树形背包(边)】【调试毒瘤】LuoGu P2015 二叉苹果树

这道题的状态转移方程极其好想,不会可以回家洗洗睡了

dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+edge[i].val)

但是!!

调试极其毒瘤!

本以为背包背的是边和点差不多,结果发现恶心至极

 1 int DP(int now,int fa)
 2 {
 3     int sum=0;
 4     for(int i=head[now],to;i!=-1;i=edge[i].nxt)
 5     {
 6         to=edge[i].to;
 7         if(to==fa)continue;
 8         leaf=0;
 9         int tt=DP(to,now);
10         sum+=tt;
11         for(int j=sum;j>=0;j--)
12         {
13             for(int k=0;k<=tt-1;k++)
14             {
15                 if(j>=k+1)dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+edge[i].val);
16             }
17         }
18     }
19     return sum+1;
20 }

来让我们慢慢分析为什么要这么写,

1.那个sum是什么

  sum返回的其实是点的数量(这样好理解),或者理解成子树的边的个数+1也行,为什么要+1,因为对于叶节点,它下面没有边,返回的不可能是0,只能是1,所以只能加一

2.枚举范围是为什么??

  首先看j的范围,我什么是sum呢?记得sum是什么吗,是子树边,加一,刚好是父节点要选的,所以可以直接就是sum,

  看k的范围,为什么是tt-1,也是因为sum的意义,减1了才是子树的边数量

  那么为什么是j-k-1呢,因为如果你在当前子节点选了k个,同时你也把根节点和子节点的边也选了,所以实际上选的是k+1个边,

  然后j>=k+1就是怕超范围

结束QAQ

上代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define N 111
 5 #define _ 0
 6 using namespace std;
 7 int n,q,u,v,w,cnt=1;
 8 int head[N],dp[N][N];
 9 struct star{int to,nxt,val;}edge[N*2];
10 inline void add(int u,int v,int w)
11 {
12     edge[cnt].nxt=head[u];
13     edge[cnt].to=v;
14     edge[cnt].val=w;
15     head[u]=cnt++;
16 }
17 int DP(int now,int fa)
18 {
19     int sum=0;
20     for(int i=head[now],to;i!=-1;i=edge[i].nxt)
21     {
22         to=edge[i].to;
23         if(to==fa)continue;
24         int tt=DP(to,now);
25         sum+=tt;
26         for(int j=min(sum,q);j>=0;j--)
27         {
28             for(int k=0;k<=tt-1;k++)
29             {
30                 if(j>=k+1)dp[now][j]=max(dp[now][j],dp[now][j-k-1]+dp[to][k]+edge[i].val);
31             }
32         }
33     }
34     return sum+1;
35 }
36 int main()
37 {
38     memset(head,-1,sizeof(head));
39     scanf("%d%d",&n,&q);
40     for(int i=1;i<n;i++)
41         scanf("%d%d%d",&u,&v,&w),
42         add(u,v,w),add(v,u,w);
43     DP(1,-1);
44     printf("%d",dp[1][q]);
45     return ~~(0^_^0);
46 }

原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10110586.html

时间: 2024-11-10 00:39:13

【树形背包(边)】【调试毒瘤】LuoGu P2015 二叉苹果树的相关文章

MZOJ 1134 &amp;&amp; LuoGu P2015 二叉苹果树

MZOJ 1134 && LuoGu P2015 二叉苹果树     [传送门] #include<bits/stdc++.h> using namespace std; const int maxn=500; int N,Q; int head[maxn],k=0; int w[maxn][maxn],f[maxn][maxn]; struct edge{ int v,w,nxt; }e[maxn<<1]; void init(){ freopen("i

luogu P2015 二叉苹果树

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

P2015 二叉苹果树[树形dp+背包]

题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树 2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 解析 一道很简单的树形dp,然而我调了半天都没调出来,就是菜. 容易看出状态\(dp[x][i]\)表示以\(

P2015 二叉苹果树 树形dp

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

P2015 二叉苹果树

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

洛谷—— P2015 二叉苹果树

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

洛谷 P2015 二叉苹果树

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

洛谷P2015 二叉苹果树(树状dp)

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

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

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