概念

给定一棵有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总结基础的更多相关文章

  1. HDU 1520.Anniversary party 基础的树形dp

    Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  2. 基础树形DP小结

    HDU 4044 Geodefense http://blog.csdn.net/zmx354/article/details/25109897 树形DP暂且先告一段落了. HDU 3586 Info ...

  3. 树形dp基础

    今天来给大家讲一下数形dp基础 树形dp常与树上问题(lca.直径.重心)结合起来 而这里只讲最最基础的树上dp 1.选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程 ...

  4. 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 ...

  5. POJ 3140.Contestants Division 基础树形dp

    Contestants Division Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10704   Accepted:  ...

  6. BZOJ1040 基环森林 找环+基础树形DP

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4752  Solved: 1831[Submit][Status ...

  7. HDU1502/Luogu1352/UVa1220 party[树形DP]

    题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri, ...

  8. 动态规划——树形dp

    动态规划作为一种求解最优方案的思想,和递归.二分.贪心等基础的思想一样,其实都融入到了很多数论.图论.数据结构等具体的算法当中,那么这篇文章,我们就讨论将图论中的树结构和动态规划的结合——树形dp. ...

  9. poj2342 Anniversary party【树形dp】

    转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4316097.html   ---by 墨染之樱花 [题目链接]http://poj.org/p ...

随机推荐

  1. Mave 下载与安装

    一,Maven 介绍 我们在开发中经常需要依赖第三方的包,包与包之间存在依赖关系,版本间还有兼容性问题,有时还需要将旧的包升级或降级,当项目复杂到一定程度时包管理变得非常重要.Maven是当前最受欢迎 ...

  2. Linux:sqlplus

    [oracle@hb shell_test]$ cat echo_time #!/bin/sh 一.最简单的调用sqlplus sqlplus -S "sys/unimas as sysdb ...

  3. sftp 上传下载 命令介绍

    sftp是Secure FileTransferProtocol的缩写,安全文件传送协议.可以为传输文件提供一种安全的加密方法. sftp与 ftp有着几乎一样的语法和功能.SFTP为 SSH的一部分 ...

  4. spring下春注解的声明式事务控制

    package com.hope.test;import com.hope.domain.Account;import com.hope.service.IAccountService;import ...

  5. SQLServer和java数据类型的对应关系

    转载自:https://www.cnblogs.com/cunkouzh/p/5504052.html SQL Server 类型 JDBC 类型 (java.sql.Types) Java 语言类型 ...

  6. Ajax异步更新网页(使用原生JavaScript)

    一.页面代码 <!DOCTYPE html> <html> <head> <title>MyHtml.html</title> <me ...

  7. C语言static关键字

    C语言static关键字 static关键字的作用,主要从在程序的生存周期.作用域和在代码段中的位置起作用. 全局变量 静态全局变量 局部变量 静态局部量 生存周期 程序运行到结束 程序运行到结束 函 ...

  8. Java中的对于多态的理解

    一.什么是多态 面向对象的三大特性:封装.继承.多态 多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同的行为方式.(发送消息就是函数调用) 实现多态的技 ...

  9. 『学了就忘』Linux系统管理 — 83、Linux中进程的查看(top命令)

    目录 1.top命令介绍 2.top命令示例 3.top命令输出项解释 4.top命令常用的实例 1.top命令介绍 top命令是用来动态显示系统中进程的命令. [root@localhost ~]# ...

  10. cron 获取下次运行时间(基于 C# + Quartz.NET)

    代码 Quartz 的 cron 支持秒,导致一些 cron 库无法准确的获得下次执行时间,这里使用 Quartz.Net 自带的方法来获取下次执行时间. //引用 Quartz CronExpres ...