「一本通 5.2 例 1」二叉苹果树 题解

解析「一本通5.2例1」二叉苹果树问题,通过动态规划求解在保留特定数量节点的情况下,二叉树中能保存的最大苹果数。文章详细介绍了状态定义、转移方程及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

「一本通 5.2 例 1」二叉苹果树


题目信息
https://loj.ac/problem/10153

题解
由根分成左子树和右子树的情况
需要保留q条边 也就是要保留j=q+1个点(必须包括根节点)
如果树根的两棵子树都为非空,设左子树保留k个,则右子树保留(j-1)-k个节点。
注:j-1是因为要包括根节点本身
状态:f[i][j]表示以i为根 保留含自己的共j个点最多能留住的苹果数。
转移方程:

f[i][j]=max(f[l[i]][k]+f[r[i]][j-1-k]+a[i]};
#include<bits/stdc++.h>
using namespace std;
int  n,q,mp[101][101],l[101],r[101],a[101],f[101][101];
void maketree(int fa)
{
	for(int i=1;i<=n;i++)
	if(mp[fa][i]>=0)
	{
	 l[fa]=i;
	 a[i]=mp[fa][i];
	 mp[fa][i]=-1;
	 mp[i][fa]=-1;
	 maketree(i);
	 break;//really imp 找到没有后开始找右儿子 	
	}
	for(int i=1;i<=n;i++)
	if(mp[fa][i]>=0)
	{
	 r[fa]=i;
	 a[i]=mp[fa][i];
	 mp[fa][i]=-1;
	 mp[i][fa]=-1;
	 maketree(i);
	 break;	
	}
}
int dp(int fa,int num)//f[i][j]是指以i为根 保留含自己的共j个点最多能留住的苹果数 
{
  if(num==0) return 0; 
  if((l[fa]==0)&&(r[fa]==0)) return a[fa];
  //到了叶子节点 直接返回a[fa](a[i]表示i指向其父亲的枝的苹果树) 
  if(f[fa][num]>0) return f[fa][num];
  //记忆化搜索 如果已经搜到了就直接返回 
  for(int k=0;k<=num-1;k++)
  f[fa][num]=max(f[fa][num],dp(l[fa],k)+dp(r[fa],num-1-k)+a[fa]);
  //左儿子保留k个点 有儿子保留(num-1)-k个点 
  return f[fa][num];
}
int main()
{
	scanf("%d%d",&n,&q);
	q++;//保留q个边相当于保留q+1个点 
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=n;j++)
	mp[i][j]=-1;//初始化 区分有0个or没有枝 
	for(int i=1;i<=n-1;i++)
	{
	 int u,v,val;
	 scanf("%d%d%d",&u,&v,&val);
	 mp[u][v]=val;//不确定方向  
	 mp[v][u]=val;
	}
	maketree(1);//以1为根建立二叉树 
	printf("%d",dp(1,q));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值