题目大意:一棵树有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;
}