选课 ( dp 树形dp 动态规划 树规)
和某篇随笔重了?!!?!?!?!?!?不管了留着吧
题目:
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b)。一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少?
输入
第一行有两个整数N,M用空格隔开。(1<=N<=200,1<=M<=150)
接下来的N行,第I+1行包含两个整数ki和si, ki表示第I门课的直接先修课,si表示第I门课的学分。若ki=0表示没有直接先修课(1<=ki<=N, 1<=si<=20)。
输出
只有一行,选M门课程的最大得分。
样例输入
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
样例输出
13
题解
多叉树转二叉树。树形dp。
1.多叉树转二叉树转法:
我们用到的是孩子兄弟法。
对于每一个节点,他在二叉树中的左孩子是在多叉树中的第一个孩子,他在二叉树中的右孩子是在多叉树中的第一个兄弟。
如上图,左边的是原来的多叉树,右边的是二叉树,其中红色线表示左孩子的关系,绿色线表示右孩子的关系。
比如节点2,在多叉树中的第一个孩子是6,那么他在二叉树中的左孩子是6。第一个兄弟是3,所以在二叉树中的右孩子是3。
为什么我们要转换呢?因为方便记忆化搜索处理状态啊!
因为输入的是一个森林,我们就通过节点0来代表一棵树的根的父亲(这是很方便的,因为输入数据就是这样的:若ki=0表示没有直接先修课)。
------------------------------------------------------------------
2.然后是树形dp。我这里用的记忆化搜索。
dfs(i,j)代表当前要考虑第i个课程及以其为根的二叉树中的子树的选择情况,j表示当前能够选择多少门课程。
根据题意可知,现在正在考虑第i门课程的情况时,必须已经选择了第i门课程在多叉树中的爹(要不选个毛啊)。所以我们可以直接略过第i门课程,去考虑第i门课程的右孩子(多叉树中的下一个兄弟),当然也不能考虑自己的左孩子(多叉树中的孩子)了。
我们还需要选第i门课程的情况。选第i门课程,就得加上这门课程的学分,然后剩余总课程--。剩下的课程可以分给自己的左孩子(多叉树中的孩子)一些,剩下的分给自己的右孩子(多叉树中的兄弟)。在dfs中,for(int k=0;k<j;k++)这里面的这个k就是给左孩子多少。那么就更新答案为。自己的学分+dfs左孩子的学分+dfs右孩子的学分。
简洁的main函数就是读入->转换->dfs并输出答案。这里我们不dfs 0,而是直接dfs 0的左孩子(之前说过0是整个森林的根),是因为防止在边界判断时候把0判断掉。
3.代码
#include <iostream>
using namespace std;
int n,m;
int a[2001],f[2001];//a[i]是某一门课程的学分 f[i]是某一门课程在多叉树中的爹
int lChild[2001],rChild[2001];//二叉树的左子树和柚子树
int dp[2001][2001];//dp[i][j]是以第i个节点为根的二叉树(注意是二叉树),能选择j门课程时候的最大学分。
void convert()//多叉树 -> 二叉树
{
for(int i=1;i<=n;i++)//遍历每一个节点
{
int fa=f[i];//这个节点的爹
if(lChild[fa]==0)lChild[fa]=i;//这个节点的爹还没有孩子,所以这个节点就是这个节点的爹的第一个孩子
else//这个节点的爹有孩子,所以这个节点在二叉树中就应该是这个节点的爹的左孩子的最右边的叶子的孩子
{
fa=lChild[fa];//暂时让变量fa变成爹的第一个孩子(二叉树中的左孩子)
while(rChild[fa])fa=rChild[fa];//循环找最右边的叶子
rChild[fa]=i;//成为最右边的叶子的右孩子
}
}
}
int dfs(int i,int j)//i是当前节点的编号,j是当前可以选择的课程数目
{
if(i<1||j<1||i>n||j>m)return 0;//边界判断
if(dp[i][j]!=0)return dp[i][j];//查备忘录
for(int k=0;k<j;k++)//选给左子树k个,自己留一个(得选自己,否则无法选左孩子),剩下的给右
dp[i][j]=max(dp[i][j],a[i]+dfs(lChild[i],k)+dfs(rChild[i],j-k-1));//自己的学分+dfs左孩子的学分+dfs右孩子的学分
dp[i][j]=max(dp[i][j],dfs(rChild[i],j));//略过自己,都给右孩子
return dp[i][j];//最后返回答案
} int main()
{
cin >> n >> m;
for(int i=1;i<=n;i++)
cin >> f[i] >> a[i];
convert();
cout << dfs(lChild[0],m) << endl;
return 0;
}
选课 ( dp 树形dp 动态规划 树规)的更多相关文章
- C++ 洛谷 2014 选课 from_树形DP
洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...
- CH5402 选课【树形DP】【背包】
5402 选课 0x50「动态规划」例题 描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了 N(N≤300) 门的选修课程,每个学生可选课程的数量 M 是 ...
- joyOI 选课 【树形dp + 背包dp】
题目链接 选课 题解 基础背包树形dp #include<iostream> #include<cstdio> #include<cmath> #include&l ...
- 洛谷$2014$ 选课 背包类树形$DP$
luogu Sol 阶段和状态都是树形DP板子题,这里只讲一下背包的部分(转移)叭 它其实是一个分组背包模型,具体理解如下: 对于一个结点x,它由它的子结点y转移而来 在子结点y为根的树中可以选不同数 ...
- luogu2014 选课 背包类树形DP
题目大意:有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b).一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少? ...
- codevs 1378 选课 (树形DP)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; ][],f[] ...
- 选课(树形DP)
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...
- cogs 1199选课(树形dp 背包或多叉转二叉
http://cogs.pro:8080/cogs/problem/problem.php?pid=vQyiJkkPP 题意:给m门课,每门课在上完其先修课后才能上,要你从中选n门课使得总学分尽可能大 ...
- [Luogu2014]选课(树形dp)
[Luogu2014]选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课 ...
随机推荐
- Monitoring tools that everyone's currently using
Although a lot of new tools have arrived since 2011, it's clear that older open source tools like Na ...
- linux yum 脚本实现
yum 位于linux /usr/bin/yum yum命令是python脚本进行编写的(python 2.6) #!/usr/bin/python2.6 import sys try: import ...
- nfs cron shell 笔记
1.nfs 2.crond 3.shell 1.准备环境: 防火墙 selinux 配置ip 2.安装软件 二进制 源码安装 3.改改配置文件 二进制:/etc/nginx/nginx.conf 源码 ...
- jdbcTemplate学习(二)
前面讲了增加.删除.更新操作,这节讲一下查询. 查询操作: (一)查询一个值(不需要注入参数) queryForObject(String sql, Class<T> requiredTy ...
- DAY5-模块与包
一.模块的介绍 1.什么是模块 #常见的场景:一个模块就是一个包含了一组功能的python文件,比如spam.py,模块名为spam,可以通过import spam使用. #在python中,模块的使 ...
- 02 mybatis环境搭建 【spring + mybatis】
1 导包 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.o ...
- 利用General框架开发RDLC报表
RDLC是微软推出的自家的报表软件,虽然没有一些第三方的报表软件强大好用,但是作为VisualStudio集成的报表工具,在客户要求不高的情况下还是非常值得一用的,本文将介绍通过General代码生成 ...
- yii2常用excel操作库
yii2使用较多的excel操作库 1."phpoffice/phpexcel" https://github.com/PHPOffice/PHPExcel/archive/1.8 ...
- ZROI2018提高day3t1
传送门 分析 我们可以用贪心的思想.对于所有并没有指明关系的数一定是将小的放在前面.于是我们按顺序在每一个已经指明大小顺序的数前面插入所有比它小且没有指明关系的数.详见代码. 代码 #include& ...
- 第三章:PCL基础3.1
架构师为了确保在PCL中所有代码风格的一致性,使得其他开发者及用户容易理解源码,PCL开发者制定并遵循着一套严格的编写规范,PCL的开发者都默认此规范. 3.1PCL推荐的命名规范 1.文件命名 1) ...