博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
『选课 有树形依赖的背包问题』
阅读量:6840 次
发布时间:2019-06-26

本文共 2129 字,大约阅读时间需要 7 分钟。

『选课 有树形依赖的背包问题』


选课(tyvj 1051)

Description

学校实行学分制。每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。学校开设了N(N < 300)门的选修课程,每个学生可选课程的数量M是给定的。学生选修了这M门课并考核通过就能获得相应的学分。

在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修。例如《Frontpage》必须在选修了《Windows操作基础》之后才能选修。我们称《Windows操作基础》是《Frontpage》的先修课。每门课的直接先修课最多只有一门。两门课也可能存在相同的先修课。每门课都有一个课号,依次为1,2,3,…。

你的任务是为自己确定一个选课方案,使得你能得到的学分最多,并且必须满足先修课优先的原则。假定课程之间不存在时间上的冲突。

Input Format

输入文件的第一行包括两个整数N、M(中间用一个空格隔开)其中1≤N≤300,1≤M≤N。

以下N行每行代表一门课。课号依次为1,2,…,N。每行有两个数(用一个空格隔开),第一个数为这门课先修课的课号(若不存在先修课则该项为0),第二个数为这门课的学分。学分是不超过10的正整数。

Output Format

输出文件只有一个数,实际所选课程的学分总数。

Sample Input

7 42 20 10 42 17 17 62 2

Sample Output

13

解析

由题意可得,课程与课程之间的先修关系构成了一棵树,在最优化问题中,我们通常是用树形\(DP\)来求解的。那么我们可以先尝试树形\(DP\)的方法:设\(f[i][j]\)代表以\(i\)为根的子树中选了\(j\)门课程的最大学分数。显然,这个状态的转移在每颗子树中都可以选取若干门课程,那么,我们首先可以得出如下的状态转移方程:

\[ f[i][j]=\max_{\sum^{|son(i)|}_{k=1}c_k=j-1}\{\sum^{|son(i)|}_{k=1}f[son_k][c_k]\}+score[i] \]
其中\(|son(i)|\)代表\(i\)的子节点个数,\(son_k\)代表其中某个子节点的编号,\(c_k\)则代表对于每一颗子树选取的课程门数,需满足:\(\sum_{k=1}^{|son(i)|}c_k=j-1\)
事实上,这是一个分组背包模型:\(j-1\)即为背包体积,每一个\(son_k\)即为一组物品,每组组物品分别有\(j-1\)个,每一个体积分别为\(c_k\),价值为\(f[son_k][c_k]\),而每组物品我们只能从中选取至多一个,使得总价值最大。
那么对于每一颗子树,我们就可以用分组背包的方程来转移了。
\[ f[i][j]=\max\{f[i][t-j]+f[son][j]\} \]
注意一个细节,没有先修课的课程,在输入中我们认为它的先修课是一个虚拟课程\(0\),那么在\(i=0\)时,背包的体积为\(j\),不需要为该门课程本身留下一个位置,所以我们可以将带有这门课程本身的状态额外的转移一次。

\(Code:\)

#include
using namespace std;const int N=300+30,M=300+30;int n,m,f[N][M],score[N]; vector < int >Link[N];inline void input(void){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int u,v; scanf("%d%d",&u,&v); Link[u].push_back(i); score[i]=v; }}inline void dp(int root){ f[root][0]=0; for(int i=0;i
0;v--) { for(int j=1;j<=v;j++) { f[root][v]=max(f[root][v],f[Son][j]+f[root][v-j]); } } } if(root!=0) for(int v=m;v>0;v--) f[root][v]=f[root][v-1]+score[root];}int main(void){ freopen("test.in","r",stdin); freopen("test.out","w",stdout); input(); dp(0); printf("%d\n",f[0][m]);}


转载于:https://www.cnblogs.com/Parsnip/p/10333684.html

你可能感兴趣的文章
DIV外区域Click后关闭DIV
查看>>
后缀数组学习笔记——罗穗骞倍增算法代码
查看>>
Automating Capistrano Password Prompts with Expect
查看>>
用 HTML5 和 Javascript 仿制一个水果忍者网页版! (直接浏览器在线玩+源代码下载)...
查看>>
设计模式简介
查看>>
删除数组中某一匹配项
查看>>
Sharepoint学习笔记—error处理-- The user does not exist or is not unique.
查看>>
CSS占位隐藏(转)
查看>>
利用jsdoc-toolkit生成javascript文档
查看>>
javascript 判断浏览器客户端
查看>>
NSString 中包含中文字符时转换为NSURL
查看>>
排序总结
查看>>
PreferenceCategory背景颜色设置
查看>>
Cocos2d-xna : 横版战略游戏开发实验4 Layer构建丰富的交互
查看>>
给孩子增加学习生物的兴趣,买了个显微镜
查看>>
代码风格 2012/10/12
查看>>
Source Code Pro - 来自 Adobe的最佳编程字体!
查看>>
Uva 11300 Spreading the Wealth
查看>>
深度拷贝
查看>>
远程桌面时自动输入“c“的解决方法
查看>>