面对美帝国主义的无端封锁,在列宁同志的带领下,我国人民艰苦创业,成功解决了这道题!下面是现场记者发回的解题总设计师的谈话:
课程树的结构是一个多叉的森林,因此可以用一个虚拟的根节点将其做成一颗树.可以按照背包问题的方法求解,但背包问题的主要代码已被美国封锁,因此我采用了多叉转二叉的方式,将多叉树转为二叉树.
定义dp数组为dp[a,b],a表示当前已经选了a门课,b表示还有b门课没有选.
在树上的每一个点,可以选择这个点,然后进入这个点的儿子和兄弟(左子树和右子树).如果不选这个点,就只有进入他的兄弟.
代码如下:
#include<bits/stdc++.h>
using namespace std;
bool falg=false;
int n,m;
int dp[310][310],point[310];
struct tree
{
int left=-1,right=-1;
}t[310];
int dg(int,int);
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int father;
scanf("%d%d",&father,point+i);
t[i].right=t[father].left;
t[father].left=i;//多叉转二叉的关键步骤在前2篇博客已经给出
}
printf("%d",dg(0,m+1));
return 0;
}
int dg(int i,int j)
{
if(i==-1)return 0;
if(j==0)return 0;
if(dp[i][j]!=-1)return dp[i][j];//记忆化
int m=-2147483647;
m=max(m,dg(t[i].right,j));//兄弟
for(int k=0;k<=j-1;k++)//在儿子里面选课的个数
{
m=max(m,dg(t[i].left,k)+dg(t[i].right,j-k-1)+point[i]);//儿子+兄弟+自己
}
dp[i][j]=m;
return m;
}