『选课 树形dp 输出方案』
<更新提示>
<第一次更新>这道题的树上分组背包的做法已经在『选课 有树形依赖的背包问题』中讲过了,本篇博客中主要讲解将多叉树转二叉树的做法,以便输出方案。
<正文>
选课
Description
学校实行学分制。每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分。学校开设了N(N < 500)门的选修课程,每个学生可选课程的数量M是给定的。学生选修了这M门课并考核通过就能获得相应的学分。
在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修。例如《Frontpage》必须在选修了《Windows操作基础》之后才能选修。我们称《Windows操作基础》是《Frontpage》的先修课。每门课的直接先修课最多只有一门。两门课也可能存在相同的先修课。每门课都有一个课号,依次为1,2,3,…。
上例中1是2的先修课,即如果要选修2,则1必定已被选过。同样,如果要选修3,那么1和2都一定已被选修过。 你的任务是为自己确定一个选课方案,使得你能得到的学分最多,并且必须满足先修课优先的原则。假定课程之间不存在时间上的冲突。
Input Format
第一行包括两个正整数N、M(中间用一个空格隔开)其中N表示待选课程总数(1≤N≤500),M表示学生可以选的课程总数(1≤M≤N)。 以下M行每行代表一门课,课号依次为1,2,…,M。每行有两个数(用一个空格隔开),第一个数为这门课的先修课的课号(若不存在先修课则该项为0),第二个数为这门课的学分。
Output Format
第一行只有一个数,即实际所选课程的学分总数。 以下N行每行有一个数,表示学生所选课程的课号。
n行学生选课的课号按从小到大的顺序输出。
Sample Input
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
Sample Output
13
2
3
6
7
解析
直接使用树上背包的方法,不便于输出方案,我们换一种思路\(dp\)。对于每一个节点,我们记录\(br[i]\)代表\(i\)一个兄弟节点的编号,\(ch[i]\)代表\(i\)一个子节点的编号。如果兄弟节点和子节点不止一个怎么办,显然,它兄弟的兄弟也是它的兄弟,它儿子的兄弟也是它的儿子,这样就可以表示所有的兄弟节点和儿子节点了,而事实上,对于每一个\(i\)我们只记录一个\(br[i]\)和\(ch[i]\),这样,本质上我们就把多叉树转换为二叉树了。
还是设\(f[x][t]\)代表以\(x\)为根的子树中选了\(t\)门课的最大学分,显然有两种转移:
\(1.\) 不取节点\(x\),直接令\(f[x][t]=f[br[x]][t]\)即可
\(2.\) 取节点\(x\)并在以\(x\)为根的子树中取一部分点,剩下的一部分点在兄弟中取,即\(f[x][t]=max\{f[br[x]][i]+f[ch[x]][t-i-1]+a[x]\}\)
利用上述两个方程即可完成树形\(dp\)。
我们可以通过同样的枚举方式得知每一次节点\(x\)是否被选,就能得到方案了。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
const int N = 520;
int n,m,br[N],ch[N],a[N],f[N][N],ans[N];
inline void input(void)
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
int fa; scanf("%d%d",&fa,&a[i]);
if ( fa == 0 ) fa = n+1;
br[i] = ch[fa];
ch[fa] = i;
}
}
inline void dp(int x,int t)
{
if ( f[x][t] > 0 ) return;
if ( x == 0 || t == 0 ) return;
dp( br[x] , t );
f[x][t] = f[br[x]][t];
for (int i=0;i<t;i++)
{
dp( br[x] , i ) , dp( ch[x] , t-i-1 );
f[x][t] = max( f[x][t] , f[br[x]][i] + f[ch[x]][t-i-1] + a[x] );
}
}
inline void solve(int x,int t)
{
if ( x == 0 || t == 0 ) return;
if ( f[x][t] == f[br[x]][t] ) return solve( br[x] , t );
for (int i=0;i<t;i++)
{
if ( f[x][t] == f[br[x]][i] + f[ch[x]][t-i-1] + a[x] )
{
solve( br[x] , i ) , solve( ch[x] , t-i-1 );
ans[x] = true; break;
}
}
}
int main(void)
{
input();
dp( ch[n+1] , m );
solve( ch[n+1] , m );
printf("%d\n",f[ch[n+1]][m]);
for (int i=1;i<=n;i++)
if ( ans[i] )
printf("%d\n",i);
return 0;
}
<后记>
『选课 树形dp 输出方案』的更多相关文章
- 『大 树形dp』
大 Description 滑稽树上滑稽果,滑稽树下你和我,滑稽树前做游戏,滑稽多又多.树上有 n 个节点,它们构成了一棵树,每个节点都有一个滑稽值. 一个大的连通块是指其中最大滑稽值和最小滑稽值之差 ...
- 『kamp 树形dp』
kamp Description jz 市的云台山是个很美丽的景区,小 x 暑期到云台山打工,他的任务是开景区的大巴. 云台山景区有 N 个景点,这 N 个景点由 N-1 条道路连接而成,我们保证这 ...
- 选课 树形DP+多叉树转二叉树+dfs求解答案
问题 A: 选课 时间限制: 1 Sec 内存限制: 128 MB 题目描述 大 学里实行学分.每门课程都有一定的学分,学生只要选修了这门课并考核通过就能获得相应的学分.学生最后的学分是他选修的各门 ...
- vijos 1180 选课 树形DP
描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得 ...
- 洛谷P2014 选课 (树形dp)
10月1日更新.题目:在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分 ...
- [vijos1880]选课<树形dp>
题目链接:https://www.vijos.org/p/1180 这是一道树形dp的裸题,唯一的有意思的地方就是用到了多叉树转二叉树 然后本蒟蒻写这一道水题就是因为以前知道这个知识点但是没有怎么去实 ...
- [Luogu P2014]选课 (树形DP)
题面 传送门:https://www.luogu.org/problemnew/show/P2014 Solution 这是一道十分经典的树形DP题,这种类型的树形DP有一种很普遍的解法. 首先,观察 ...
- Codevs1378选课[树形DP|两种做法(多叉转二叉|树形DP+分组背包)---(▼皿▼#)----^___^]
题目描述 Description 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修 ...
- codevs 1378选课 树形DP
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; ],tr[] ...
随机推荐
- 【转】面试题:实现一个队列,这个队列除了有EnQueue, DeQueue操作,还有一个Max操作,三个操作复杂度都是O(1)
1.每次 新元素进栈的时候,栈里面的元素需要排序 2.让最小的或者最大的元素位于栈顶,这样就可以在O(1)时间内获得最小或者最大的值了, ------ 3.上面的想法 不能保证,进栈(进了队列)之 ...
- 分布式文件系统HDFS练习
本次作业要求:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/3310 start-all.sh确保开启服务 在HDFS中为hadoop ...
- LocalDateTime的一些用法
包括获取当前时间,指定特定时间.进行时间的加减等 LocalDateTime localDateTime3 = LocalDateTime.now(); LocalDate.now(); LocalT ...
- Java多线程编程核心技术-第3章-线程间通信-读书笔记
第 3 章 线程间通信 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大 ...
- java.util.ConcurrentModificationException异常;java.util.ConcurrentModificationException实战
写代码遇到这个问题,很多博客文章都是在反复的强调理论,而没有对应的实例,所以这里从实例出发,后研究理论: 一.错误产生情况 1 .字符型 (1)添加 public static void main(S ...
- 查看linux服务器配置信息命令
查看 cpu信息: cat /proc/cpuinfo 查看内存信息: grep MemTotal /proc/meminfo 查看操作系统信息: uname -a 查看centos版本信息: cat ...
- Layui 模板引擎中的 日期格式化
原文:https://www.jianshu.com/p/948a474b5ed7 原文:https://blog.csdn.net/DCFANS/article/details/92064112 模 ...
- 元素的alt和title有什么异同?
①alt作为图片的替代文字出现,title作为图片的解释文字出现. ②alt属性应用较少,如img.area.input中,title应用较多,如a.form.input.还有div.p这些块级元素都 ...
- luogu p2622关灯问题II
luogu p2622关灯问题II 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[ ...
- 【JZOJ6236】【20190628】启程的日子
题目 给你一个\(n \times m\)的01矩阵 你需要用一些矩阵加减出这个矩阵 求最少的步数,并输出方案 需要满足构造出的01矩阵是一个四联通块 $ n , m \le 500 $ 题解 答案 ...