树形DP 洛谷P2014 选课
洛谷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门课程的最大得分。
好困啊~~~
这道题做的不好。
一开始的做法:
设\(f(i)(j)\)表示在以i为根的子树中,选择j个点并且一定选择i的最大价值。
状态倒是设对了。但是转移就不会了。
想的是树上的分组背包。
将当前点的每个儿子看成一类物品,然后就可以枚举这一类物品中选多少个。
应该是没问题,但是太困写不动了。。。
而且我犯了一个错误就是对于当前的点u,应该枚举一层这个点的子树中选择多少个,所以我们应该记录当前的这个数的大小,并用其作为上界,但我是写了一个记忆化搜索每一次将传入的参数t当做上界,就不对了。
好了,感觉我的做法思路很乱套。
开始说一说正确做法吧。
状态很好设:设\(f(i)(j)\)表示在以i为根的子树中,选择j个点并且一定选择i的最大价值。
重点是怎么去推。
这里用到了一个东西叫做多叉转二叉。也就是说我们要记录当前节点的子树大小作为枚举上界,所以我们可以每一次将当前点现在所枚举到的子树的大小加上,就是开一个变量记录当前的子树大小,在转移之前先将当前枚举到的子节点的size加上。
这里有一个DP的思想,个人感觉类似记忆化搜索吧,挺重要的,就是我们当前要用v去转移u的状态,那么肯定的,我们应该知道v的状态(当然也可以在转移时记忆化搜索出v的状态),所以我们在转移u之前就应该先将v转移好。
#include<iostream>
#include<cstdio>
using namespace std;
const int wx=3017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
struct e{
int nxt,to;
}edge[wx*2];
int n,m,num,x;
int head[wx],a[wx],f[317][317],size[wx];
void add(int from,int to){
edge[++num].nxt=head[from];
edge[num].to=to;
head[from]=num;
}
int dfs(int u){
f[u][1]=a[u];int tot=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;tot+=dfs(v);
for(int j=tot;j>=1;j--){
for(int k=1;k<j;k++){
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
}
}
}
return tot;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++){
x=read();a[i]=read();
add(x,i);
}
dfs(0);
printf("%d\n",f[0][m+1]);
return 0;
}
//f[i][j]表示在以i为根的子树中选择j个点并且一定选i这个点的最大价值
//f[i][j]=max(f[i][j],f[v][k]+a[v]+f[i][j-k])
树形DP 洛谷P2014 选课的更多相关文章
- 洛谷 P2014 选课(树形背包)
洛谷 P2014 选课(树形背包) 思路 题面:洛谷 P2014 如题这种有依赖性的任务可以用一棵树表示,因为一个儿子要访问到就必须先访问到父亲.然后,本来本题所有树是森林(没有共同祖先),但是题中的 ...
- 洛谷P2014 选课 (树形dp)
10月1日更新.题目:在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分 ...
- 洛谷P2014 选课
首先分析题目,这是一道树形dp的题目,是树形背包类的问题,以为每门课的先修课只有一门,所以这一定可以 构成一个森林结构,于是我们可以设计一个虚拟的根节点作为森林的根. 状态转移方程如下 dp[v][k ...
- 洛谷 P2014 选课
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...
- 洛谷 P2014 选课 && caioj 1108 树形动态规划(TreeDP)3:选课
这里的先后关系可以看成节点和父亲的关系 在树里面,没有父亲肯定就没有节点 所以我们可以先修的看作父亲,后修的看作节点 所以这是一颗树 这题和上一道题比较相似 都是求树上最大点权和问题 但这道题是多叉树 ...
- 洛谷P2014——选课
题目:https://www.luogu.org/problemnew/show/P2014 树状DP,注意枚举当前子树中选几个时的边界. 代码如下: #include<iostream> ...
- 洛谷—— P2014 选课
https://www.luogu.org/problem/show?pid=2014 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课 ...
- C++ 洛谷 2014 选课 from_树形DP
洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...
- 洛谷$2014$ 选课 背包类树形$DP$
luogu Sol 阶段和状态都是树形DP板子题,这里只讲一下背包的部分(转移)叭 它其实是一个分组背包模型,具体理解如下: 对于一个结点x,它由它的子结点y转移而来 在子结点y为根的树中可以选不同数 ...
随机推荐
- 两个stack实现一个queue
package com.hzins.suanfa; import java.util.Stack; /** * 两个stack实现一个queue * @author Administrator * * ...
- log4j No appenders could be found for logger
在main中加一句:BasicConfigurator.configure();
- linux命令学习笔记(37):date命令
在linux环境中,不管是编程还是其他维护,时间是必不可少的,也经常会用到时间的运算,熟练运用date命令 来表示自己想要表示的时间,肯定可以给自己的工作带来诸多方便. .命令格式: date [参数 ...
- BZOJ5324 JXOI2018 守卫
传送门 这是我见过的为数不多的良心九怜题之一 题目大意 给定一段$n$个点构成的折线,第$i$个折点的坐标是$(i,h_i)$,你可以在$i$点放置一个视野,定义$i$能看到$j$当且仅当$i$处有视 ...
- 调试 ASP 程序脚本
调试 ASP 脚本 无论您的计划多么精密.经验多么丰富,脚本错误 (bug) 可能在最初就使您的 ASP 服务器端的脚本无法正确运行.也就是说调试,即查找和纠正脚本错误,对开发一个成功的和强健的 AS ...
- Boost库之asio io_service以及run、run_one、poll、poll_one区别
一.io_service的作用 io_servie 实现了一个任务队列,这里的任务就是void(void)的函数.Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,r ...
- 宽字符wchar_t和窄字符char区别和相互转换
转自:http://blog.csdn.net/nodeathphoenix/article/details/7416725 1. 首先,说下窄字符char了,大家都很清楚,就是8bit表示的b ...
- event.keyCode 事件属性
转自:http://www.runoob.com/jsref/event-key-keycode.html <!DOCTYPE html> <html> <head> ...
- java 设置Cookie值
原文地址:http://blog.csdn.net/lansetiankong12/article/details/52622654 /** * 读取所有cookie * 注意二.从客户端读取Cook ...
- centos7 安装mysql 5.7多实例
一. Mysql多实例即一台服务器上运行多个Mysql服务进程 ,开启不同的服务端口,通过不同的socket 监听不同的服务端口来提供各自的服务. 二. Mysql多例有以下几个特点: 1. 有效利 ...