题目描述

在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有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

算法:

树形DP

 

分析:

这道题一拿起来就感觉它好像是一个背包问题。但其实普通的有依赖性背包问题是无法解决这种有互相依赖的像图一样的问题,然而我们又发现先修课和后续课存在着关联,于是我们就可以用树形DP。

 

假如按照之前套路走,我们应该构建一棵多叉树,在这棵树上进行动规。嗯,没问题。

 

但是,第一数据范围可能会卡掉几个点,第二,代码量会非常大,而且状态转移很难写。

 

那么我们用图论的方法吧!

 

嗯,没问题。

 

但是请想想图论的算法解决这道题又有点杀鸡用牛刀了。而且码量绝对不小。

 

那么,我们可以用多叉树转二叉树的思想来解决这个问题。

 

怎么转呢?

 

先想一个问题,在一棵多叉树中,兄弟的兄弟还是兄弟,儿子的兄弟也还是自己的儿子。兄弟的儿子就与自己没什么关联。

 

那么我们通过这个性质,构造一棵二叉树,令其满足任意一棵子树的根节点的非空左儿子是自己原来的儿子,非空右儿子是自己原来的兄弟。那么一棵树就建好了。

 

然后,想状态转移方程。自己的兄弟是和自己有同等的发展机遇的,所以根节点能经历的事,能分到的课程数,它现在的右儿子(兄弟)也同样能经历。所以也要先遍历。

至于儿子,可以儿子和兄弟一起分课程,那么一起去两个儿子也是可行的。

那么我们得到以下方程:f[root][len]=max(f[root][len],max(f[b[root]][len],f[b[root]][i]+f[c[root]][len-i-1]+w[root]));

设f[root][len]表示以root为根节点的时候取len门课程可以取得的最大收益。那么状态转移的状态就有完全不变、不选根节点(只选兄弟)和孩子兄弟一起分这三种情况,很好理解。

 

对于存储,可以选择链式前向星,用存图的方式来存储,那么dfs的时候就有些奇怪。

也可以用类似链表的形式存上一条边,同样快捷。

 

上代码:

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cctype>
  5. using namespace std;
  6.  
  7. int w[],b[],c[],f[][],n,m,t; //w是权值,b是兄弟,c是孩子
  8.  
  9. inline int read() //读入优化
  10. {
  11. int f=,x=;
  12. char c=getchar();
  13. while (!isdigit(c))
  14. f=c=='-'?-:,c=getchar();
  15. while (isdigit(c))
  16. x=(x<<)+(x<<)+(c^),c=getchar();
  17. return x*f;
  18. }
  19.  
  20. void dfs(int root,int len) //记忆化
  21. {
  22. if (f[root][len]>=) //出现过,直接返回
  23. return;
  24. if (root==||len==) //到边界了
  25. {
  26. f[root][len]=;
  27. return;
  28. }
  29. int i;
  30. dfs(b[root],len); //兄弟和自己有同等的发展机遇
  31. for (i=;i<len;i++) //兄弟孩子一起分
  32. {
  33. dfs(b[root],i);
  34. dfs(c[root],len-i-);
  35. f[root][len]=max(f[root][len],max(f[b[root]][len],f[b[root]][i]+f[c[root]][len-i-]+w[root]));
  36. }
  37. return;
  38. }
  39.  
  40. int main()
  41. {
  42. int i,j;
  43. n=read();
  44. m=read();
  45. memset(f,-,sizeof(f)); //作死,初始化
  46. for (i=;i<=n;i++)
  47. {
  48. t=read();
  49. w[i]=read();
  50. if (!t)
  51. t=n+;
  52. b[i]=c[t]; //模拟链表
  53. c[t]=i;
  54. }
  55. dfs(c[n+],m);
  56. printf("%d",f[c[n+]][m]);
  57. return ;
  58. }

总结一点,树规的dfs很好理解,从哪开始,从哪结束,从哪输出。

 

嗯,就这样了。

【洛谷P2014】选课的更多相关文章

  1. 洛谷 P2014 选课(树形背包)

    洛谷 P2014 选课(树形背包) 思路 题面:洛谷 P2014 如题这种有依赖性的任务可以用一棵树表示,因为一个儿子要访问到就必须先访问到父亲.然后,本来本题所有树是森林(没有共同祖先),但是题中的 ...

  2. 树形DP 洛谷P2014 选课

    洛谷P2014 选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门 ...

  3. 洛谷P2014——选课

    题目:https://www.luogu.org/problemnew/show/P2014 树状DP,注意枚举当前子树中选几个时的边界. 代码如下: #include<iostream> ...

  4. 洛谷P2014 选课 (树形dp)

    10月1日更新.题目:在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分 ...

  5. 洛谷P2014 选课

    首先分析题目,这是一道树形dp的题目,是树形背包类的问题,以为每门课的先修课只有一门,所以这一定可以 构成一个森林结构,于是我们可以设计一个虚拟的根节点作为森林的根. 状态转移方程如下 dp[v][k ...

  6. 洛谷 P2014 选课

    题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...

  7. 洛谷—— P2014 选课

    https://www.luogu.org/problem/show?pid=2014 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课 ...

  8. 洛谷 P2014 选课 && caioj 1108 树形动态规划(TreeDP)3:选课

    这里的先后关系可以看成节点和父亲的关系 在树里面,没有父亲肯定就没有节点 所以我们可以先修的看作父亲,后修的看作节点 所以这是一颗树 这题和上一道题比较相似 都是求树上最大点权和问题 但这道题是多叉树 ...

  9. C++ 洛谷 2014 选课 from_树形DP

    洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...

  10. 洛谷P2014 TYVJ1051 选课

    题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...

随机推荐

  1. 3dContactPointAnnotationTool开发日志(二九)

      今天想着在Windows平台上跑通那个代码,不过它的官网上写的支持平台不包括windows,但我还是想试试,因为看他的依赖好像和平台的关系不是特别大.   看了下它的py代码,不知道是py2还是p ...

  2. 敏捷冲刺DAY4

    一. 每日会议 1. 照片 2. 昨日完成工作 登录界面的进一步完善 服务器搭建 建立数据库 3. 今日完成工作 发布和提供需求功能的实现 用户修改自己的信息 用户界面设计 管理员界面设计 4. 工作 ...

  3. QTemporaryDir及QTemporaryFile建立临时目录及文件夹

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QTemporaryDir及QTemporaryFile建立临时目录及文件夹     本文地址 ...

  4. webgl example1

    <!doctype html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  5. html5兼容

    You can download the latest version of HTML5shiv from github or reference the CDN version at https:/ ...

  6. xstream 解析xml报文

    一.xml一种格式的数据转换为对象 pom.xml引入 <!--javaBean和XML的双向转换--> <dependency> <groupId>com.tho ...

  7. SQL中的逻辑运算符

    逻辑运算符和比较运算符一样,都是返回 true 或 false 值得布尔数据类型.   运算符 行为 ALL 如果一个比较集中全部都是 true ,则值为 true AND 如果两个布尔值表达式均为 ...

  8. shell脚本学习—正则表达式

    正则表达式概念.特点 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”, 这个“规则字符串”用来表达对字符串的一种过滤辑. 给定一个 ...

  9. [十二]SpringBoot 之 servlet

    Web开发使用 Controller 基本上可以完成大部分需求,但是我们还可能会用到 Servlet.Filter.Listener.Interceptor 等等. 当使用spring-Boot时,嵌 ...

  10. NewCaffe

    NewCaffe