题目描述

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

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

 

上代码:

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
using namespace std; int w[],b[],c[],f[][],n,m,t; //w是权值,b是兄弟,c是孩子 inline int read() //读入优化
{
int f=,x=;
char c=getchar();
while (!isdigit(c))
f=c=='-'?-:,c=getchar();
while (isdigit(c))
x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
} void dfs(int root,int len) //记忆化
{
if (f[root][len]>=) //出现过,直接返回
return;
if (root==||len==) //到边界了
{
f[root][len]=;
return;
}
int i;
dfs(b[root],len); //兄弟和自己有同等的发展机遇
for (i=;i<len;i++) //兄弟孩子一起分
{
dfs(b[root],i);
dfs(c[root],len-i-);
f[root][len]=max(f[root][len],max(f[b[root]][len],f[b[root]][i]+f[c[root]][len-i-]+w[root]));
}
return;
} int main()
{
int i,j;
n=read();
m=read();
memset(f,-,sizeof(f)); //作死,初始化
for (i=;i<=n;i++)
{
t=read();
w[i]=read();
if (!t)
t=n+;
b[i]=c[t]; //模拟链表
c[t]=i;
}
dfs(c[n+],m);
printf("%d",f[c[n+]][m]);
return ;
}

总结一点,树规的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. 操作系统作业一——仿CMD

    实验一.CMD实验 2014商软2  卓宇靖  4238 一.        实验目的 (1)掌握命令解释程序的原理: (2)掌握简单的DOS调用方法: (3)掌握C语言编程初步. 二.        ...

  2. windows(32位 64位)下python安装mysqldb模块

    windows(32位 64位)下python安装mysqldb模块 www.111cn.net 编辑:mengchu9 来源:转载 本文章来给各位使用在此windows系统中的python来安装一个 ...

  3. HDU4788_Hard Disk Drive

    水题. 但是我写挫了一个地方,Wa了三发.好吧,不能忍了. 还有,本屌不知道如何用printf输出%,哪位学过C++的大仙知道这是什么情况?  告诉我一声啊. #include <iostrea ...

  4. hdu 6375 百度之星 度度熊学队列

    题目链接 Problem Description 度度熊正在学习双端队列,他对其翻转和合并产生了很大的兴趣. 初始时有 N 个空的双端队列(编号为 1 到 N ),你要支持度度熊的 Q 次操作. ①1 ...

  5. lucence学习系列之一 基本概念

    1. Lucence基本概念 Lucence是一个java编写的全文检索类库,使用它可以为一个应用或者站点增加检索功能. 它通过增加内容到一个全文索引来完成检索功能.然后允许你基于这个索引去查询,返回 ...

  6. bzoj4815[CQOI2017]小Q的格子

    题意 不简述题意了,简述题意之后这道题就做出来了.放个原题面. 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理. 每当小Q不知道如何解决时,就只好向 ...

  7. CentOS 7下安装pptp服务端手记 ok

    主要配置步骤 1. 安装前检查系统支持 2. 安装必要包 3. 修改相关配置文件 4. 设置开机自动启动 pptpd, iptables 5. iptables配置网络 6. 阿里云ECS可能还需要几 ...

  8. [学习笔记]kruskal重构树 && 并查集重构树

    Kruskal 重构树 [您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树 kruskal是一个性质优秀的算法 加入的边是越来越劣的 科学家们借这个特点尝试搞一点事 ...

  9. [转]从头开始 GAN

    1 前言 GAN的火爆想必大家都很清楚了,各种GAN像雨后春笋一样冒出来,大家也都可以名正言顺的说脏话了[微笑脸].虽然目前GAN的酷炫应用还集中在图像生成上,但是GAN也已经拓展到NLP,Robot ...

  10. Codeforces 395 D.Pair of Numbers

    D. Pair of Numbers time limit per test 2 seconds memory limit per test 256 megabytes input standard ...