Codeforces-1249F-树上dp

题目传送门

题目大意:一棵树有n个点,每个点有点权,需要选一些点使得点权和最大,要求选出的点任何两个点之间的距离都大于k,n<=200

完全不知道数据为什么这么小,,,明明O(n*k)的做法就是可以过的啊
对于每一个点来说,我们维护一个大小为k的F数组,F[i]代表着如果从当前点的子树里选出相互之间距离大于k的点集,并且点集中所有的点都距离当前点距离大于等于i,这样的点集的权值和是多少。
有了这样一个F[i],我们针对于每一个点都可以用他子节点的F数组来更新,只要保证点集之间的距离大于k,就可以贪心的选择了,是不是很暴力呢

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct data_p{int hed,v,f[205];}pot[205];
struct data_l{int nxt,to;}lin[2005];
int n,k,ans,top=0;
void add_l(int a,int b)
{lin[++top].to=b;lin[top].nxt=pot[a].hed;pot[a].hed=top;}
void get_f(int a,int b)
{
	pot[a].f[0]+=pot[b].f[k-1];
	for(int i=1;i<k;i++)
	{
		int j=k-i;
		if(j>=i)pot[a].f[i]=max(pot[b].f[j-1]+pot[a].f[i],pot[a].f[j]+pot[b].f[i-1]);
		else pot[a].f[i]+=pot[b].f[i-1];
	}
}
void dp(int a,int fa)
{
	for(int i=pot[a].hed;i;i=lin[i].nxt)
	{
		int b=lin[i].to;
		if(b==fa)continue;
		dp(b,a);	get_f(a,b);
	}
	pot[a].f[0]+=pot[a].v;
	for(int i=k-2;i>=0;i--)
	pot[a].f[i]=max(pot[a].f[i],pot[a].f[i+1]);
	/*
	cout<<a<<"*"<<endl;
	for(int i=0;i<=k;i++)
	cout<<pot[a].f[i]<<" ";cout<<endl;
	*/
}
int main()
{
	scanf("%d%d",&n,&k);k++;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&pot[i].v);
		for(int j=1;j<=k;j++)pot[i].f[j]=0;
	}
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add_l(x,y);add_l(y,x);
	}
	dp(1,1);
	printf("%d",pot[1].f[0]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值