题目描述
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?
输入输出格式
输入格式:
第一行有两个整数N,M用空格隔开。(1<=N<=300,1<=M<=300)
接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。
输出格式:
只有一行,选M门课程的最大得分。
输入输出样例
输入样例#1:
7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2
输出样例#1:
13
题目地址:https://www.luogu.org/problemnew/show/P2014
个人思路:
- 本质上仍然是背包问题,但是这里把背包问题转化到了树上
- 所以,在dfs的同时进行背包dp(分组背包)即可
#include<cstdio>
#include<iostream>
using namespace std;
int score[1010],ans,n,m,f[1010][1010],head[1010],cnt;
struct edge{
int from,to,nxt;
}e[1010];
void add(int from,int to){
e[++cnt].from=from;
e[cnt].to=to;
e[cnt].nxt=head[from];
head[from]=cnt;
}
void dp(int x){
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
dp(v);
for(int t=m;t;t--)//循环当前选课总门数(背包体积)
for(int j=t;j;j--){//循环更深子树上的选课门数(组内物品)
if(t-j>=0)
f[x][t]=max(f[x][t],f[x][t-j]+f[v][j]);
ans=max(ans,f[x][t]);
}
}
if(x!=0)
for(int t=m;t;t--){
f[x][t]=f[x][t-1]+score[x];
ans=max(ans,f[x][t]);
}
}
int main(){
ans=-2000000000;
cin>>n>>m;
int fa;
for(int i=1;i<=n;i++){
cin>>fa>>score[i];
add(fa,i);
}
dp(0);
printf(\"%d\\n\",ans);
return 0;
}
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。


