题目大意
给一棵
N
N
N个结点的有根树,结点由
1
1
1到
N
N
N标号,根结点的标号为
1
1
1。每个结点上有一个物品,第
i
i
i个结点上的物品价值为
v
i
v_i
vi。
你需要从所有结点中选出若干个结点,使得对于任意一个被选中的结点,其到根的路径上所有的点都被选中,并且选中结点的个数不能超过给定的上限
l
i
m
lim
lim。在此前提下,你需要最大化选中结点上物品的价值之和。求这个最大的价值之和。
题目解析
设 F [ i ] [ j ] F[i][j] F[i][j] 表示在当前已经结束了 d f s dfs dfs的所有结点中选择 j j j个,所能获得的最大价值和。
d f s dfs dfs一个儿子前,将父亲的 F F F值直接复制给儿子,儿子的 d f s dfs dfs结束后,再合并入父亲的 d f s dfs dfs值,这里的 F [ s o n ] [ ∗ ] F[son][*] F[son][∗]是不包含结点 s o n son son的情况的,因此将儿子 s o n son son的情况并入 i i i时,强制选择 s o n son son上的物品,并取最大值。
A n s = M a x ( A n s , F [ 1 ] [ 0 Ans=Max(Ans,F[1][0 Ans=Max(Ans,F[1][0~ l i m ] + 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;
}