题目链接
题意:
给你一个森林,有
个点,每个点有一个价值,能选某个点的前提是它的所有祖先节点都被选,让你求只能选
个节点的最大价值。
题解:
首先先把所有没有父节点的点向
号点连边,让森林变成一棵树,然后我们由叶子向根dp,设
为在根节点为
的子树里选
个节点的最大获益。当
时,
。当
时,设
,
这可以转化为一个分组背包,每个子树看作一组,从每组中至多选一个物品,体积为 ,价值为 ,这样对这个树形结构进行背包dp的转移就行。
复杂度 ,注意 号点是个虚拟节点,实际上不需要被选, 就是最终答案。
洛谷2014选课代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,son[310][310],dp[310][310],val[310],cnt[310];
void dfs(int x)
{
for(int i=1;i<=cnt[x];++i)
{
int y=son[x][i];
dfs(y);
for(int j=m;j>=0;--j)
{
for(int k=j;k>=0;--k)
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]);
}
}
if(x!=0)
{
for(int i=m;i>=1;--i)//注意倒叙枚举
dp[x][i]=dp[x][i-1]+val[x];//x本身需要占一门课
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
int x;
scanf("%d%d",&x,&val[i]);
son[x][++cnt[x]]=i;
}
dfs(0);
printf("%d\n",dp[0][m]);
return 0;
}