『没有上司的舞会 树形DP』
<更新提示>
<第一次更新>
<正文>
树形DP入门
有些时候,我们需要在树形结构上进行动态规划来求解最优解。
例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子树的深度,形成一个子问题重叠的结构,是符合动态规划前提的。在设计动态规划算法时,一般由节点由深到浅的顺序来作为\(DP\)的阶段。\(DP\)的状态表示中,数组的第一维通常表示子树根节点的编号。大多数时候,我们用递归的形式实现树形动态规划。先在它的每个子节点上递归求出最优解,再在返回时求解当前节点的最优解。
下面我们通过一道入门例题来讲解。
没有上司的舞会(TYVJ1052 CODEVS1380)
Description
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。
Input Format
第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0,0。
Output Format
输出最大的快乐指数。
Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
Sample Output
5
Hint
Limitation
各个测试点1s
解析
通过分析可以发现,职员和上司之间的关系可以看作为是一个树形结构,又是最优解问题,可以尝试树形\(DP\)。
根据之前我们对树形\(DP\)的初步了解,我们先设置\(DP\)的状态,并将根节点编号作为第一维。分析题意,我们发现一个人是否参加舞会只和他的直接上司有关,所以我们可以把第二维设为\(0/1\),这样,\(f[i][0/1]\)代表以i号节点为根节点的子树结构中的最大快乐指数值之和,\(0\)代表\(i\)号职员不参加晚会,\(1\)代表\(i\)号职员参加晚会,这样的状态,是满足最优子结构的。
利用阶段和之前的状态建立关系。如果i参加晚会,则他的下属不能参加晚会,如果他不参加晚会,则他的下属可以参加晚会,当然,也可以不参加。 那么,我们就可以写出状态转移方程:
\\2.f[i][0]=\sum_{s\in Son(i)}max(f[s][1],f[s][0])
\]
其中,\(Son(i)\)代表节点i的子节点集合。
本题当中,我们还需要找到有根树的根,即没有上司的职员,然后从他开始进行\(DP\)求解。最终,\(DP\)的目标状态是\(max(f[root][1],f[root][0])\)。时间复杂度为\(O(n)\)。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
const int N=6000+80;
int n,h[N]={},f[N][2]={},vis[N]={};
vector < int > son[N];
inline void read(int &k)
{
int x=0,w=0;char ch;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
k=(w?-x:x);return;
}
inline void input(void)
{
read(n);
for(int i=1;i<=n;i++)read(*(h+i));
for(int i=1;i<n;i++)
{
int f,s;
read(s),read(f);
vis[s]=true;
son[f].push_back(s);
}
}
inline void dp(int root)
{
f[root][0]=0;f[root][1]=h[root];
for(int i=0;i<son[root].size();i++)
{
int S=son[root][i];
dp(S);
f[root][0]+=max(f[S][1],f[S][0]);
f[root][1]+=f[S][0];
}
}
inline void solve(void)
{
memset(f,0,sizeof f);
int root;
for(int i=1;i<=n;i++)
{
if(!vis[i]){root=i;break;}
}
dp(root);
printf("%d\n",max(f[root][0],f[root][1]));
}
int main(void)
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
input();
solve();
return 0;
}
总结
通过一道例题,我们对树形DP建立的初步的认识。但是,在更复杂的题目中,我们需要学习更多的技巧,例如,出来自顶向下的递归以外,我们还可以运用图上DP的方法,用自底向上的拓扑序来执行树形DP,但是实现更为复杂,通常来说,这样的DP已经足够。
在更多的题目中,树是以一张N个点,N-1条边的无向图的形式给出的,这样的话我们还需要找出树的根,一般是用深搜的方法。
<后记>
『没有上司的舞会 树形DP』的更多相关文章
- [luogu]P1352 没有上司的舞会[树形DP]
本Lowbee第一次写树形DP啊,弱...一个变量写错半天没看出来...... 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点 ...
- 洛谷P1352 没有上司的舞会——树形DP
第一次自己写树形DP的题,发个博客纪念`- 题目来源:P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结 ...
- CodeVS1380 没有上司的舞会 [树形DP]
题目传送门 没有上司的舞会 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个 ...
- 没有上司的舞会 树形dp
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- P1352 没有上司的舞会——树形DP入门
P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员 ...
- P1352 没有上司的舞会[树形dp]
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- P1352 没有上司的舞会&&树形DP入门
https://www.luogu.com.cn/problem/P1352 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的 ...
- 洛谷 P1352 没有上司的舞会 树形DP板子
luogu传送门 题目描述: 某大学有n个职员,编号为1~n. 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司. 现在有个周年庆宴会,宴会每邀请来一个职员都会 ...
- 【codevs1380】没有上司的舞会 树形dp
题目描述 Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个快乐指数.现在有个周年庆宴会,要求与会职员的快乐指数 ...
随机推荐
- UOJ#7. 【NOI2014】购票 点分治 斜率优化 凸包 二分
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ7.html 题解 这题是Unknown的弱化版. 如果这个问题出在序列上,那么显然可以CDQ分治 + 斜率 ...
- sql server DbHelperSQL类
using JKTAC_LMIS.Entity; using System; using System.Collections; using System.Collections.Generic; u ...
- 【Java并发编程二】Java并发包
1.Java容器 1.1.同步容器 Vector ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔,当数组大小不满足时 ...
- Android应用程序如何使用Internet资源?
思路:连接Internet资源-->分析XML资源-->使用Download Manager下载文件 Android的Internet连接模型和用于分析Internet数据源的Java技术 ...
- SpringBoot整合多数据源实现
项目架构 1.导入相关依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...
- Linux Kernel C语言编程范式
介绍 不同的编程语言具有不同的抽象原语(如下),有的原语抽象层次低,有的原语抽象层次高.其中函数式.DSL是这几年十分热门的编程语言概念. 过程式抽象原语:变量 对象式抽象原语:对象 函数式抽象原语: ...
- MyBatis3系列__04CRUD以及参数处理
本文将会简单介绍一下MyBatis的CRUD以及结合源码讲解一下MyBatis对参数的处理. 作为一个ORM框架,最基本的使用也就是CRUD了,MyBatis提供了两种方法:xml配置文件和动态注解. ...
- [CF1140C]Playlist
Description: 给你n首歌,每首歌有一个长度\(a_i\)和美丽度\(b_i\) 现在可以选出最多k首,动听值为\(\sum a_i*min_{\sum b_i}\) Hint: \(n \ ...
- c++链表基本操作
#include <stdlib.h> #include <malloc.h> #include <stdio.h> typedef struct Node { i ...
- 在 Vim 中优雅地查找和替换(转)
总有人问我 Vim 中能不能查找,当然能!而且是超级强的查找! 这篇文章来详细介绍 Vim 中查找相关的设置和使用方法. 包括查找与替换.查找光标所在词.高亮前景/背景色.切换高亮状态.大小写敏感查找 ...