首页 > 其他分享 >P2015 二叉苹果树

P2015 二叉苹果树

时间:2023-07-12 15:15:04浏览次数:48  
标签:max 子树 int P2015 tr 二叉 -- 为根 苹果树

原题链接戳这里

思考过程

一眼树状dp+背包dp
每一根树枝占用 1 空间 带来的价值由题目输入

设计 f[u][i] 表示在考虑以 u 为根的子树时 分配给它 i 根树枝 所能达到的最大价值

于是在以 u 为根的子树中想要新拓展一个以 v 为根的子树时

有转移方程 f[u][i]=max(f[u][i],f[u][i-k-1]+f[v][k]+w)
——由 u 至 v ,总共空间为 i ,分给以 v 为根的子树空间为 k
是否选择加入以 v 为根的子树 为 01 背包 注意倒序循环

这里的 i-k-1 是因为由 u 至 v 本身就需要连接一条边

初版代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define N 115
#define il inline
#define Inf 0x3f3f3f3f

int n,m;
int x,y,z;
int sz[N];
int f[N][N];

struct node{
	int to,next,w;
}tr[N<<1];
int cnt,head[N];

il int read()
{
	int x=0;
	bool f=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar())
		if(ch=='-')
			f=0;
	for(;isdigit(ch);ch=getchar())
		x=(x<<1)+(x<<3)+ch-'0';
	return f?x:(~(x-1));
}

void add(int u,int v,int w)
{
	tr[++cnt].to=v;
	tr[cnt].w=w;
	tr[cnt].next=head[u];
	head[u]=cnt;
}

void dfs(int u,int fa)
{
	for(int i=head[u];i!=-1;i=tr[i].next)
	{
		int v=tr[i].to;
		if(v==fa)continue;
//		cout<<u<<"->"<<v<<endl;
		dfs(v,u);
		for(int j=m;j>=1;j--)
		{
			for(int k=j-1;k>=0;k--)
			{
				
				f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+tr[i].w);
			}
		}
	}
}

int main()
{
	n=read();m=read();
	for(int i=0;i<=n;i++)head[i]=-1;
	for(int i=1;i<n;i++)
	{
		x=read();y=read();z=read();
		add(x,y,z);
		add(y,x,z);
	}
	dfs(1,0);
	cout<<f[1][m];
}
 

一些似乎有用的小优化

对着转移过程仔细思考一下

for(int j=m;j>=1;j--)
{
	for(int k=j-1;k>=0;k--)
	{	
		f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+tr[i].w);
	}
}

这里的 j 是为以 u 为根的子树留出的空间
而 k 是为以 v 为根的子树留出的空间

那么有没有一种可能 这些子树根本没有那么多树枝来占用空间呢

于是可以在 dfs 的过程中统计子树中的树枝数量
在 dp转移 过程中就可以减小一些时间复杂度了(也许微不足道?)

最终代码(节选 dfs 部分)

点我查看代码喔~
void dfs(int u,int fa)
{
	for(int i=head[u];i!=-1;i=tr[i].next)
	{
		int v=tr[i].to;
		if(v==fa)continue;
//		cout<<u<<"->"<<v<<endl;
		dfs(v,u);
        sz[u]+=sz[v]+1;//在这里统计了树枝数量
		for(int j=min(m,sz[u]);j>=1;j--)
		{
			for(int k=min(sz[v],j-1);k>=0;k--)
			{
				
				f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+tr[i].w);
			}
		}
	}
}

标签:max,子树,int,P2015,tr,二叉,--,为根,苹果树
From: https://www.cnblogs.com/pigAlg/p/17547332.html

相关文章

  • 算法学习day14二叉树part01-94、144、145
    packageSecondBrush.Tree;importjava.util.ArrayList;importjava.util.List;/***94.二叉树的中序遍历*给定一个二叉树的根节点root,返回它的中序遍历。**/publicclassBinaryTreeInorderTraversal_94{publicList<Integer>inorderTraversal(Tre......
  • LeetCode 剑指 Offer 08. 二叉树的下一个节点
    题目:二叉树的下一个节点给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。(树的后继)注意:如果给定的节点是中序遍历序列的最后一个,则返回空节点;二叉树一定不为空,且给定的节点一定不是空节点;解题思路二叉树的中序遍历:{[左子树],根节点,[右子树]}如图所示......
  • 1382. 将二叉搜索树变平衡
    给你一棵二叉搜索树,请你返回一棵平衡后的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。如果有多种构造方法,请你返回任意一种。如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过1,我们就称这棵二叉搜索树是平衡的。输入:root=[1,null,2,null,3,null,4,null,......
  • #551. 合并果子(二叉堆)
    #551.合并果子_#551.合并果子方法一:手写堆(题解->陶)#include<bits/stdc++.h>usingnamespacestd;constintmaxn=10000+10;intn,heap[maxn],size=0;voidup(intp)//二叉小根堆向上调整(子节点小于父节点就调整){while(p>1){if(heap[p]<heap[p/2]){......
  • 【算法】根据二叉树的级别返回排序后的元素列表
    根据给定的Node树节点,返回包含按级别排序的树中元素的列表,这意味着根元素位于第一位,然后根子元素(从左到右)位于第二位和第三位,依此类推。1publicclassNode2{3publicNodeLeft;4publicNodeRight;5publicintValue;67publicNode(No......
  • P3378 【模板】二叉堆
    [洛谷]P3378【模板】堆方法一手写堆最小堆插入从新增的最后一个结点的父结点开始,用要插入元素向下过滤上层结点(相当于要插入的元素向上渗透)voidsiftdown(inti)//传入一个需要向下调整的结点编号i,这里传入1,即从堆的顶点开始向下调整{intt,flag=0;//flag用来标......
  • 1644 题「二叉树的最近公共祖先 II
    对于这道题来说,p和q不一定存在于树中,所以你不能遇到一个目标值就直接返回,而应该对二叉树进行完全搜索(遍历每一个节点),如果发现p或q不存在于树中,那么是不存在LCA的。  ......
  • 二叉树解题的
    先在开头总结一下,思维模式分两类:https://labuladong.github.io/algo/2/19/33/1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个traverse函数配合外部变量来实现,这叫「遍历」的思维模式。2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,......
  • 题:二叉树中m是n的祖先,通过(后序遍历)可以找到m到n的路径
     选项:先序?中序?后序?层次? 题解:1.首先是对路径的解释:访问一个结点x时,栈中结点恰好是x结点的所有祖先,从栈底到栈顶所有结点加上x结点,就构成了从根结点到x结点的一条路径。2.分析:为什么不是先序遍历?(第一次做题时以为这个路径指的是遍历的结果,那先序自然就满足,但这个路径不是遍历......
  • LeetCode 108. 将有序数组转换为二叉搜索树
    题目链接:LeetCode108.将有序数组转换为二叉搜索树题意:给你一个整数数组nums,其中元素已经按升序排列,请你将其转换为一棵高度平衡二叉搜索树。高度平衡二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过1」的二叉树。解题思路:(递归)O(n)递归建立整......