【洛谷P2014】选课
题目描述
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有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】选课的更多相关文章
- 洛谷 P2014 选课(树形背包)
洛谷 P2014 选课(树形背包) 思路 题面:洛谷 P2014 如题这种有依赖性的任务可以用一棵树表示,因为一个儿子要访问到就必须先访问到父亲.然后,本来本题所有树是森林(没有共同祖先),但是题中的 ...
- 树形DP 洛谷P2014 选课
洛谷P2014 选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门 ...
- 洛谷P2014——选课
题目:https://www.luogu.org/problemnew/show/P2014 树状DP,注意枚举当前子树中选几个时的边界. 代码如下: #include<iostream> ...
- 洛谷P2014 选课 (树形dp)
10月1日更新.题目:在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分 ...
- 洛谷P2014 选课
首先分析题目,这是一道树形dp的题目,是树形背包类的问题,以为每门课的先修课只有一门,所以这一定可以 构成一个森林结构,于是我们可以设计一个虚拟的根节点作为森林的根. 状态转移方程如下 dp[v][k ...
- 洛谷 P2014 选课
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...
- 洛谷—— P2014 选课
https://www.luogu.org/problem/show?pid=2014 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课 ...
- 洛谷 P2014 选课 && caioj 1108 树形动态规划(TreeDP)3:选课
这里的先后关系可以看成节点和父亲的关系 在树里面,没有父亲肯定就没有节点 所以我们可以先修的看作父亲,后修的看作节点 所以这是一颗树 这题和上一道题比较相似 都是求树上最大点权和问题 但这道题是多叉树 ...
- C++ 洛谷 2014 选课 from_树形DP
洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...
- 洛谷P2014 TYVJ1051 选课
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...
随机推荐
- 虚拟机中安装 centOS,本地安装 SSH 连接 - 01
下面把自己安装 centOS 的过程记录下,选取的版本是 centOS6.8 ,下载地址在脚本之家 down 的 : 阿里云 x64 http://mirrors.aliyun.com/centos/ ...
- Java知识点整理(二)
List.Set.Map典型实现 HashMap/ConcurrentHashMap Java线程池 Java线程池详解 如何更好的使用JAVA线程池 Spring MVC Spring MVC架构浅 ...
- 第193天:js---Math+Error+Number+Object总结
一.Math 随机选取 //随机选取 function getRandom (begin,end){ return Math.floor(Math.random()*(end-begin))+begi ...
- elsarticle模板 去掉摘要前后的两条横线
参考:http://www.newsmth.net/nForum/#!article/TeX/316697?au=ericfire 如图:使用elsarticle模板修改PDF格式,去掉摘要前后的横线 ...
- jsp和js中获取项目路径名
一.jspa.<%=request.getContextPath()%>//结果:/projectNameb.${pageContext.request.contextPath}//结果: ...
- 【BZOJ3566】概率充电器(动态规划)
[BZOJ3566]概率充电器(动态规划) 题面 BZOJ Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: "采用全新纳米级加工 ...
- python基础----内置函数----匿名函数(lambda)
Python3版本所有的内置函数: 1. abs() 获取绝对值 >>> abs(-) >>> abs() >>> abs() >>& ...
- winform布局 FlowLayoutPanel的控件
http://www.cnblogs.com/moon-mountain/archive/2011/09/08/2171232.html 1.采用流布局:工具箱里边容器里有一个:FlowLayoutP ...
- Mybatis中jdbcType和javaType对应关系
Mybatis中javaType和jdbcType对应关系 JDBC Type Java Type CHAR String VARCHAR ...
- 图像处理之中值滤波介绍及C实现
1 中值滤波概述 中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号平滑处理技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值. 中值滤波的基本原理是把数字图像或数字序 ...