[Jzoj] 4814.tree

博客围绕有根树结点选择问题展开。给定N个结点的有根树,每个结点有物品及价值,需选若干结点,保证所选结点到根路径上的点都被选,且数量不超上限lim,以最大化价值和。给出了解题思路,设F[i][j]表示相关最大价值和,还给出了求解答案的公式。

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

题目大意

给一棵NNN个结点的有根树,结点由111NNN标号,根结点的标号为111。每个结点上有一个物品,第iii个结点上的物品价值为viv_ivi
你需要从所有结点中选出若干个结点,使得对于任意一个被选中的结点,其到根的路径上所有的点都被选中,并且选中结点的个数不能超过给定的上限limlimlim。在此前提下,你需要最大化选中结点上物品的价值之和。求这个最大的价值之和。

题目解析

F[i][j]F[i][j]F[i][j] 表示在当前已经结束了dfsdfsdfs的所有结点中选择jjj个,所能获得的最大价值和。

dfsdfsdfs一个儿子前,将父亲的FFF值直接复制给儿子,儿子的dfsdfsdfs结束后,再合并入父亲的dfsdfsdfs值,这里的F[son][∗]F[son][*]F[son][]是不包含结点sonsonson的情况的,因此将儿子sonsonson的情况并入iii时,强制选择sonsonson上的物品,并取最大值。

Ans=Max(Ans,F[1][0Ans=Max(Ans,F[1][0Ans=Max(Ans,F[1][0~lim]+a[1])lim]+a[1])lim]+a[1])

代码

#include<bits/stdc++.h>
using namespace std;
int n,lim,ans;
int a[3005],f[3005][3005];

int ls[3005],cnt;
struct edge
{
	int v,next;
}e[10005];
void ins(int x,int y)
{
	e[++cnt].v=y;e[cnt].next=ls[x];ls[x]=cnt;
}

void dfs(int x,int fa)
{
	for(int i=ls[x];i!=0;i=e[i].next)
	 if(e[i].v!=fa)
	 {
	   for(int j=1;j<=lim;j++) f[e[i].v][j]=f[x][j];
	   dfs(e[i].v,x);
	   for(int j=1;j<=lim;j++) f[x][j]=max(f[x][j],f[e[i].v][j-1]+a[e[i].v]);
	 }
}

int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	cin>>n>>lim;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1,u,v;i<n;i++) cin>>u>>v,ins(u,v),ins(v,u);
	dfs(1,0);
	for(int i=1;i<=lim;i++) ans=max(ans,f[1][i-1]+a[1]);
	cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值