题解_P2014选课全面胜利,全国人民齐欢唱

面对美帝国主义的无端封锁,在列宁同志的带领下,我国人民艰苦创业,成功解决了这道题!下面是现场记者发回的解题总设计师的谈话:

课程树的结构是一个多叉的森林,因此可以用一个虚拟的根节点将其做成一颗树.可以按照背包问题的方法求解,但背包问题的主要代码已被美国封锁,因此我采用了多叉转二叉的方式,将多叉树转为二叉树.

定义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;
}

猜你喜欢

转载自www.cnblogs.com/Hdgs3-blog/p/10891036.html