树形DP总结基础
概念
给定一棵有N个节点的树(通常是无根树,也就是有N-1条无向边),我们可以任选一个节点为根节点,从而定义出每个节点的深度和每棵子树的根。
在树上设计动态规划算法时,一般就以节点从深到浅(子树从小到大)的顺序作为DP的“阶段”。DP的状态表示中,第一维通常是节点编号(代表以该节点为根的子树)。大多数时候,我们采用递归的方式实现树形动态规划。对于每个节点x,先递归在它的每个子节点上进行DP,在回溯时,从子节点向节点x进行状态转移。
简单点说,其实,就是dfs,但这个dfs,时间复杂度要小的很多,并且,具体操作使用数组来模拟不同情况
并且,很多时候,线性dp的可以演变成树形DP,如背包
应用
1.最大独立子集
2.树的重心
3.树的直径
例题
最大独立子集 没有上司的晚会
题目描述
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起参加宴会。 输入格式
第一行一个整数N。(1≤N≤6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128≤Ri≤127) 接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。 最后一行输入0,0。 输出格式
第1行:输出最大的快乐指数。样例
样例输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
样例输出
5
分析
首先拿到这个题,就会先把根给求出来
然后,分析题意,其实,如果选fa,那,son一定不行,但不选fa,son可选可不选,这时,我们就会想到,打dfs,或dp,但又想想,dfsO(2^n),肯定不好,dp,虽然好像可以,但,好像没有阶段,于是,就要用树形DP
dp[x][0] =max(dp[s][0],dp[s][1])
dp[x][1] = H[x] + dp[son][0](son∈Son(x)
比如dp[i][1]表示以i号节点为子树的根,当它参会时整棵子树的快乐指数和;dp[i][0]表示以i号节点为子树的根,当它不参会时整棵子树的快乐指数和
很明显,这就是由叶节点,一点点的传到根
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100050];
int x,y;
vector<int>g[100005];
int dp[10005][2];
int fa[100005];
int root;
void dfs(int x)
{
dp[x][1]=a[x];
dp[x][0]=0;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
dfs(v);
dp[x][1]+=dp[v][0];
dp[x][0]+=max(dp[v][0],dp[v][1]);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n-1;i++)
{
scanf("%d %d",&x,&y);
g[y].push_back(x);
fa[x]=1;
}
for(int i=1;i<=n;i++)
{
if(!fa[i])
{
root=i;
break;
}
}
dfs(root);
printf("%d",max(dp[root][1],dp[root][0]));
}
树的重心
首先,我们要知道,什么是重心
树的重心定义为,当把节点x去掉后,其最大子树的节点个数最少(或者说成最大连通块的节点数最少),那么节点x就是树的重心。
他有以下几个性质
1、删除重心后所得的所有子树,节点数不超过原树的1/2,一棵树最多有两个重心,且相邻;
2、树中所有节点到重心的距离之和最小,如果有两个重心,那么它们距离之和相等;
3、两个树通过一条边合并,新的重心在原树两个重心的路径上;
4、树删除或添加一个叶子节点,重心最多只移动一条边。
还有,一棵树,重心最多2个,n%2= =0有2个,n%2= =1有一个
运用第一个性质,可以解决大多数问题
题目描述
树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值。树可能存在多个重心。如下图,当去掉点1后,树将分成两个连通块:(2,4,5),(3,6,7),则最大的连通块包含节点个数为3。若去掉点2,则树将分成3个部分,(4),(5),(1,3,6,7)最大的连通块包含4个节点;第一种方法可以得到更小的最大联通分量。可以发现,其他方案不可能得到比3更小的值了。所以,点1是树的重心。
输入格式
输入:第一行一个整数n,表示树的结点个数。(n<100) 接下来n-1行,每行两个数i,j。表示i和j有边相连。 输出格式
输出:第一行一个整数k,表示重心的个数。 接下来K行,每行一个整数,表示重心。按从小到大的顺序给出。样例
样例输入
7
1 2
1 3
2 4
2 5
3 6
3 7
样例输出
1
1
分析
运用第一个性质,我们可以排除那些不是重心的,然后,输出剩下的
可以统计任选一个节点为根,把无根树变成有根树,然后dp[i]表示以i为根的子树的节点个数
dp[i]=∑dp[son]+1
这只是部分子树,还有当前节点的长辈,节点总数为n-dp[now],然后在做比较
#include<bits/stdc++.h>
using namespace std;
int n;
int x,y;
int dp[100054];
vector<int>g[10005];
vector<int>ans;
int vis[10005]; void dfs(int x)
{
bool flag=1;
dp[x]=1;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(vis[v])
{
continue;
}
vis[v]=1;
dfs(v);
dp[x]+=dp[v];
if(dp[v]>n/2)
{
flag=0;
}
}
if(n-dp[x]>n/2)
{
flag=0;
}
if(flag)
{
ans.push_back(x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
vis[1]=1;
dfs(1);
printf("%d\n",ans.size());
if(ans.size()==1)
{
printf("%d",ans[0]);
}
else
{
printf("%d\n%d",min(ans[0],ans[1]),max(ans[0],ans[1]));
}}
树的直径
概念
给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点(两个节点肯定都是叶子节点)之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。后者通常也可称为直径。
题目描述
给定一个有个节点的树,树以个点条边的无向图形式给出, 求树的直径。 输入格式
输入的第1行为包含了一个正整数,为这棵二叉树的结点数。 接下来N行,每行有个正整数,表示有一条从到的无向边。 输出格式
输出包括1个正整数,为这棵二叉树的直径。样例
样例输入
10
1 2
1 3
2 4
4 5
4 6
1 7
5 8
7 9
7 10
样例输出
6
分析
跑2个dfs,第一个求以根为起点的最短距离,第二个求一最长距离终点为起点的最长距离,ans为第二个
#include <bits/stdc++.h>
using namespace std;
int n;
int x, y;
vector<int> g[100005];
int dp[1000005];
int ans;
int jl;
void dfs(int x, int fa) {
if (ans < dp[x]) {
ans = dp[x];
jl = x;
}
for (int i = 0; i < g[x].size(); i++) {
int v = g[x][i];
if (v == fa) {
continue;
}
dp[v] = dp[x] + 1;
dfs(v, x);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d %d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
ans = 0;
dp[1] = 0;
dfs(1, 0);
ans = 0;
dp[jl] = 0;
dfs(jl, 0);
printf("%d", ans);
}
树形DP总结基础的更多相关文章
- HDU 1520.Anniversary party 基础的树形dp
Anniversary party Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- 基础树形DP小结
HDU 4044 Geodefense http://blog.csdn.net/zmx354/article/details/25109897 树形DP暂且先告一段落了. HDU 3586 Info ...
- 树形dp基础
今天来给大家讲一下数形dp基础 树形dp常与树上问题(lca.直径.重心)结合起来 而这里只讲最最基础的树上dp 1.选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程 ...
- hdu 1561 The more, The Better(树形dp,基础)
The more, The Better Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- POJ 3140.Contestants Division 基础树形dp
Contestants Division Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10704 Accepted: ...
- BZOJ1040 基环森林 找环+基础树形DP
1040: [ZJOI2008]骑士 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4752 Solved: 1831[Submit][Status ...
- HDU1502/Luogu1352/UVa1220 party[树形DP]
题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...
- 动态规划——树形dp
动态规划作为一种求解最优方案的思想,和递归.二分.贪心等基础的思想一样,其实都融入到了很多数论.图论.数据结构等具体的算法当中,那么这篇文章,我们就讨论将图论中的树结构和动态规划的结合——树形dp. ...
- poj2342 Anniversary party【树形dp】
转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4316097.html ---by 墨染之樱花 [题目链接]http://poj.org/p ...
随机推荐
- Mysql资料 锁机制
目录 一.简介 二.类型 三.操作 四.死锁 第一种情况 第二种情况 第三种情况 一.简介 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同 ...
- SimpleCursorAdapter 原理和实例
SimpleCursorAdapter 1. 原理参见下面代码注释 Cursor cursor = dbHelper.fetchAllCountries(); //cursor中存储需要加载到list ...
- noVNC连接多台远程主机
noVNC是一个HTML5 VNC客户端,采用HTML5 websockets.Canvas和JavaScript实现,noVNC被普遍应用于各大云计算.虚拟机控制面板中,比如OpenStack Da ...
- CF955C Sad powers 题解
Content 给你 \(q\) 个询问,每次询问 \([l,r]\) 这个区间内满足 \(x=a^p(a>0,p>1)\) 的 \(x\) 的数量. 数据范围:\(1\leqslant ...
- CF1036D Vasya and Arrays 题解
Content 给定两个长度分别为 \(n\) 和 \(m\) 的数列 \(A,B\).你需要将两个数列都恰好分成 \(k\) 份,使得两个数列中第 \(i(i\in[1,k])\) 份的元素和对应相 ...
- 使用容器挂载NFS
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistent-volumes nfs 标准协议 v2 v3 v4 ...
- MySQL查询列必须和group by字段一致吗?
@ 目录 场景:查询各部门薪水最高的员工. 方法一: 方法二: MySQL group by是如何决定哪一条数据留下的? 分组前的数据: 那么target list和group by column不匹 ...
- ABP VNext框架中Winform终端的开发和客户端授权信息的处理
在ABP VNext框架中,即使在它提供的所有案例中,都没有涉及到Winform程序的案例介绍,不过微服务解决方案中提供了一个控制台的程序供了解其IDS4的调用和处理,由于我开发过很多Winform项 ...
- Linux C(++)获取可执行程序完整路径
代码 #include <sys/statfs.h> #include <string> #include <iostream> #include <limi ...
- 【LeetCode】186. Reverse Words in a String II 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 每个单词单独翻转+总的翻转 日期 题目地址:https ...