题目大意
选择k个祖先,将他们的人品指数(可能为负数)加起来。但必须要满足这个要求:如果除自己的父母之外的某个祖先被选了,那么他的下一代必需要选(不允许跳过某一代选择更远的祖先)。
求选择祖先的最优方案,使得他的人品值最大。
题目解析
很明显,是一个二叉树,每个节点最多存在两个父节点
由于必须满足不允许跳过某一代选择更远的祖先,所以这是一个树形DP
设 f[i][j] 表示到了编号为 i 的点,选了 j 个数的最大人品值。
设1号结点也算入一个有权值的点,则1号结点的值就是0。
设 表示以i号结点为根结点的子树的结点总数。那么:
我们可以得到如下转移方程:
ans=f[1][k+1]
代码
#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[105],l[105],r[105],f[105][105];
int dfs(int lev,int num) //lev表示编号为lev的点 , num表示选了num个数的最大人品值。
{
if(f[lev][num]!=0) return f[lev][num];
if(num==0) return f[lev][num]=0; //若没有点分给当前这个点,则为0
if(lev==0) return f[lev][num]=-1e8; //如果为0则不存在这个节点,返回一个较小的负数。
if(num==1) return f[lev][num]=a[lev];//若只分了一个点,则只能为自己
int ans=-1e8;
for(int i=0;i<num;i++)
{
int t=a[lev]+dfs(l[lev],i)+dfs(r[lev],num-i-1);
ans=max(ans,t);
}
f[lev][num]=ans;
return ans;
}
int main()
{
cin>>n>>k;
for(int i=2;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>l[i]>>r[i];
cout<<dfs(1,k+1); //根节点是1号,加上自己共有k+1个要选
return 0;
}