[Luogu P2014]选课 (树形DP)
题面
传送门:https://www.luogu.org/problemnew/show/P2014
Solution
这是一道十分经典的树形DP题,这种类型的树形DP有一种很普遍的解法。
首先,观察题目,我们把这道题转换一下:给定一颗树,选出包含1号节点(根)的一颗子树,使得点权和最大。
我们可以这样子定义状态:
设f[i][j] 表示以i为根节点的子树,选出j个节点,所能达到的最大点权值。
对于二叉树来说,转移很显然,就是枚举左子树分配多少个节点,就可以对应的得出右子树能分配到多少个节点,对所有情况取最大值就好。
对于多叉树来说,问题就没有那么简单了,这里,我们有两个方案可以解决这个问题:
一是多叉树转二叉树,
二是树上背包。
因为我不会多叉树转二叉树,所以在这里我主要讲一讲第二种方法。
我们一般在树上做的是多重背包问题。
我以本题为例子,讲一下树上如何做多重背包。
首先,我们肯定要一层循环枚举子树(可以类似为背包问题中枚举第几件物品)。
第二层循环我们得枚举当前以节点的子树能分配的节点数(可以类似为背包问题中枚举背包容量)
*这一层循环一定要从后往前枚举,类似与背包压在一维做的做法*
第三层循环我们就可以枚举当前子树分配多少个节点了(可以类似多重背包中枚举第i件物品要几件)
下面是这种枚举在这道题应用的代码:
1 for(int i=0;i<int(e[x].size());i++)//枚举子树
2 {
3 int temp=dfs(e[x][i]);//先把子树的f递归下去算出来
4 tot+=temp;//tot记录到当前子树为止总节点数
5 for(int j=tot;j>=1;j--)//枚举自己这颗树的总分配数
6 for(int k=0;k<=temp;k++)//枚举子树分配多少个节点
7 if(j-k>=1)
8 f[x][j]=max(f[x][j],f[x][j-k]+f[e[x][i]][k]);
9 }
树上背包一般看上去是三重循环,非常恐怖。
但事实上,根据一堆证明(不会证),其复杂度为两重循环。
所以复杂度应该是O(能过)
复杂度是O(N*N*M)
Code
树上背包有成吨的细节,建议参考代码
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
long long read()
{
long long x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=300+10;
vector <int> e[N];
long long n,m,f[N][N],v[N];
int dfs(int x)
{
int tot=1;
f[x][1]=v[x];
for(int i=0;i<int(e[x].size());i++)
{
int temp=dfs(e[x][i]);
tot+=temp;
for(int j=tot;j>=1;j--)
for(int k=0;k<=temp;k++)
if(j-k>=1)
f[x][j]=max(f[x][j],f[x][j-k]+f[e[x][i]][k]);
}
return tot;
}
int main()
{
n=read(),m=read();
for(int i=0;i<=n;i++)
e[i].reserve(4);
for(int i=1;i<=n;i++)
{
e[read()].push_back(i);
v[i]=read();
} dfs(0); printf("%lld",f[0][m+1]);
return 0;
}
正解(c++)
[Luogu P2014]选课 (树形DP)的更多相关文章
- 洛谷P2014 选课 (树形dp)
10月1日更新.题目:在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分 ...
- 选课 树形DP+多叉树转二叉树+dfs求解答案
问题 A: 选课 时间限制: 1 Sec 内存限制: 128 MB 题目描述 大 学里实行学分.每门课程都有一定的学分,学生只要选修了这门课并考核通过就能获得相应的学分.学生最后的学分是他选修的各门 ...
- vijos 1180 选课 树形DP
描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得 ...
- 『选课 树形dp 输出方案』
这道题的树上分组背包的做法已经在『选课 有树形依赖的背包问题』中讲过了,本篇博客中主要讲解将多叉树转二叉树的做法,以便输出方案. 选课 Description 学校实行学分制.每门的必修课都有固定的学 ...
- [vijos1880]选课<树形dp>
题目链接:https://www.vijos.org/p/1180 这是一道树形dp的裸题,唯一的有意思的地方就是用到了多叉树转二叉树 然后本蒟蒻写这一道水题就是因为以前知道这个知识点但是没有怎么去实 ...
- 树上背包DP Luogu P2014 选课
#include <cstdio> #include <cctype> #include <cstring> #include <algorithm> ...
- 【题解】Luogu p2014 选课 树型dp
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...
- Codevs1378选课[树形DP|两种做法(多叉转二叉|树形DP+分组背包)---(▼皿▼#)----^___^]
题目描述 Description 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修 ...
- P2014 选课 (树形动规)
题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...
随机推荐
- STM32与CH455g通信测试(仅键盘)
1.概述 CH455是数码管显示驱动和键盘扫描控制芯片.CH455内置时钟振荡电路,可以动态驱动4位数码管或者32只LED:同时还可以进行28键的键盘扫描:CH455通过SCL和SDA组成的2线串行接 ...
- 05 C语言的数据类型
C语言的数据类型 在C 中,数据类型是用来声明不同类型的变量或函数的一个广泛的概念.变量的数据类型决定了变量存储占用的空间大小,以及如何去解释存储的位模式. C 中的数据类型可分为以下几大类: 序号 ...
- Activity的常用控件
TimerPick(时间控件)public Integer getCurrentHour() //返回当前设置的小时public Integer getCurrentMinute()//返回当前设置的 ...
- c#之task与thread区别及其使用
如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...
- python数据清洗
盖帽法 分箱法 简单随机抽和分层抽
- 用Pycharm创建指定的Django版本
最近在学习胡阳老师(the5fire)的<Django企业级开发实战>,想要使用pycharm创建django项目时,在使用virtualenv创建虚拟环境后,在pycharm内,无论如何 ...
- 很多人都搞不清楚C语言和C++的关系!今天我们来一探究竟为大家解惑~
最近,身边有许多小伙伴已经开始学习编程了,但是呢,学习又会碰到许多的问题,其中作为新手小白提到最多的问题就是编程语言的选择. 每次遇到这种问题,看起来很简单,但是又有很多小伙伴搞不清编程语言之间的关系 ...
- 【贪心算法】CF Emergency Evacuation
题目大意 vjudge链接 给你一个车厢和一些人,这些人都坐在座位上,求这些人全部出去的时间最小值. 样例1输入 5 2 71 11 21 32 32 44 45 2 样例1输出 9 样例2输入 50 ...
- linux(centos8):安装java jdk 14 (java 14.0.2)
一,下载jdk14 官方网站: https://www.oracle.com/java/ 下载页面: https://www.oracle.com/cn/java/technologies/javas ...
- 第二十三章 Firewalld的防火墙
一.防火墙基本概述 在CentOS7系统中集成了多款防火墙管理工具,默认启用的是firewalld(动态防火墙管理器)防火墙管理工具,Firewalld支持CLI(命令行)以及GUI(图形)的两种管理 ...