您的位置:首页 > 其它

Luogu P2014 选课___背包+树形dp

2018-03-20 21:11 260 查看

题目大意:

现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。给出每一门课的先修课ki和学分si,一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?

ki=0时表示没有先修课

1<=ki<=N, 1<=si<=20

1<=N<=300,1<=M<=300

题解:

一个树形dp跟背包的结合

设f[i][j]表示以i为根的子树中选j门课能够获得的最高学分

然后枚举它所有的儿子,

设k为i的一个儿子,它用了l的体积,

l保证严格≤j-1 //此时i≠0

那么f[i,j]=min(f[i][j],f[k][l]+f[i][j-l])

最后将f[i,j]加上对应的学分,j≥1

代码:

#include<bits/stdc++.h>
#define N 305

using namespace std;

int n,m,x,f

,listr
,next
,a
;

void tree_dp(int dep)
{
f[dep][0]=0;
int k=listr[dep];
while (k)
{
tree_dp(k);
for (int i=n; i>=0; i--)
for (int j=i; j>=0; j--)
f[dep][i]=max(f[dep][i],f[dep][i-j]+f[k][j]);
k=next[k];
}
if (dep!=0)
{
for (int i=n; i>0; i--)
f[dep][i]=f[dep][i-1]+a[dep];
}
}

int main()
{
scanf("%d%d",&m,&n);
for (int i=1; i<=m; i++)
{
scanf("%d%d",&x,&a[i]);
next[i]=listr[x];
listr[x]=i;
}
tree_dp(0);
printf("%d\n",f[0]
);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: