树形DP求树的最小支配集,最小点覆盖,最大独立集
一:最小支配集
考虑最小支配集,每个点有两种状态,即属于支配集合或者不属于支配集合,其中不属于支配集合时此点还需要被覆盖,被覆盖也有两种状态,即被子节点覆盖或者被父节点覆盖.总结起来就是三种状态,现对这三种状态定义如下:
1):dp[i][0],表示点 i 属于支配集合,并且以点 i 为根的子树都被覆盖了的情况下支配集中所包含最少点的个数.
2):dp[i][1],表示点 i 不属于支配集合,且以 i 为根的子树都被覆盖,且 i 被其中不少于一个子节点覆盖的情况下支配集所包含最少点的个数.
3):dp[i][2],表示点 i 不属于支配集合,且以 i 为根的子树都被覆盖,且 i 没被子节点覆盖的情况下支配集中所包含最少点的个数.即 i 将被父节点覆盖.
对于第一种状态,dp[i][0]含义为点 i 属于支配集合,那么依次取每个儿子节点三种状态中的最小值,再把取得的最小值全部加起来再加 1,就是dp[i][0]的值了.即只要每个以 i 的儿子为根的子树都被覆盖,再加上当前点 i,所需要的最少的点的个数,DP转移方程如下:
dp[i][0] = 1 + ∑(u 取 i 的子节点)min(dp[u][0], dp[u][1], dp[u][2])
对于第三种状态,dp[i][2]含义为点 i 不属于支配集合,且 i 被其父节点覆盖.那么说明点 i 和点 i 的儿子节点都不属于支配集合,所以点 i 的第三种状态之和其儿子节点的第二种状态有关,方程为:
dp[i][2] = ∑(u 取 i 的子节点)dp[u][1]
对于第二种状态,略有些复杂.首先如果点 i 没有子节点那么 dp[i][1]应该初始化为 INF;否则为了保证它的每个以 i 的儿子为根的子树被覆盖,那么要取每个儿子节点的前两种状态的最小值之和,因为此时点 i 不属于支配集,不能支配其子节点,所以子节点必须已经被支配,与子节点的第三种状态无关.如果当前所选状态中每个儿子都没被选择进入支配集,即在每个儿子的前两种状态中,第一种状态都不是所需点最小的,那么为了满足第二种状态的定义(因为点 i 的第二种状态必须被其子节点覆盖,即其子节点必须有一个属于支配集,如果此时没有,就必须强制使一个子节点的状态为状态一),需要重新选择点 i 的一个儿子节点为第一种状态,这时取花费最少的一个点,即取min(dp[u][0] - dp[u][1])的儿子节点 u,强制取其第一种状态,其他的儿子节点取第二种状态,DP转移方程为:
if(i 没有子节点) dp[i][1] = INF
else dp[i][1] = ∑(u 取 i 的子节点)min(dp[u][0], dp[u][1]) + inc
其中对于 inc 有:
if(上面式子中的 ∑(u 取 i 的子节点)min(dp[u][0], dp[u][1]) 中包含某个 dp[u][0], 即存在一个所选的最小值为状态一的儿子节点) inc = 0
else inc = min(dp[u][0] - dp[u][1]) (其中 u 取点 i 的儿子节点)
代码:
void DP(int u, int p) {// p 为 u 的父节点
dp[u][] = ;
dp[u][] = ;
bool s = false;
int sum = , inc = INF;
for(int k = head[u]; k != -; k = edge[k].next) {
int to = edge[k].to;
if(to == p) continue;
DP(to, u);
dp[u][] += min(dp[to][], min(dp[to][], dp[to][]));
if(dp[to][] <= dp[to][]) {
sum += dp[to][];
s = true;
}
else {
sum += dp[to][];
inc = min(inc, dp[to][] - dp[to][]);
}
if(dp[to][] != INF && dp[u][] != INF) dp[u][] += dp[to][];
else dp[u][] = INF;
}
if(inc == INF && !s) dp[u][] = INF;
else {
dp[u][] = sum;
if(!s) dp[u][] += inc;
}
}
二:最小点覆盖
对于最小点覆盖,每个点只有两种状态,即属于点覆盖或者不属于点覆盖:
1):dp[i][0]表示点 i 属于点覆盖,并且以点 i 为根的子树中所连接的边都被覆盖的情况下点覆盖集中所包含最少点的个数.
2):dp[i][1]表示点 i 不属于点覆盖,且以点 i 为根的子树中所连接的边都被覆盖的情况下点覆盖集中所包含最少点的个数.
对于第一种状态dp[i][0],等于每个儿子节点的两种状态的最小值之和加 1,DP转移方程如下:
dp[i][0] = 1 + ∑(u 取 i 的子节点)min(dp[u][0], dp[u][1])
对于第二种状态dp[i][1],要求所有与 i 连接的边都被覆盖,但是点 i 不属于点覆盖,那么点 i 的所有子节点就必须属于点覆盖,即对于点 i 的第二种状态与所有子节点的第一种状态有关,在数值上等于所有子节点第一种状态的和.DP转移方程如下:
dp[i][1] = ∑(u 取 i 的子节点)dp[u][0]
代码:
void DP(int u, int p) {// p 为 u 的父节点
dp[u][] = ;
dp[u][] = ;
for(int k = head[u]; k != -; k = edge[k].next) {
int to = edge[k].to;
if(to == p) continue;
DP(to, u);
dp[u][] += min(dp[to][], dp[to][]);
dp[u][] += dp[to][];
}
}
三:最大独立集
对于最大独立集,每个点也只有两种状态,即属于点 i 属于独立集或者不属于独立集两种情况:
1):dp[i][0]表示点 i 属于独立集的情况下,最大独立集中点的个数.
2):dp[i][1]表示点 i 不属于独立集的情况下.最大独立集中点的个数.
对于第一种状态dp[i][0],由于 i 点属于独立集,所以它的子节点都不能属于独立集,所以对于点 i 的第一种状态,只和它的子节点的第二种状态有关.等于其所有子节点的第二种状态的值加 1,DP转移方程如下:
dp[i][0] = 1 + ∑(u 取 i 的子节点) dp[u][1]
对于第二种状态dp[i][1],由于点 i 不属于独立集,所以子节点可以属于独立解,也可以不属于独立集,所取得子节点状态应该为数值较大的那个状态,DP转移方程:
dp[i][1] = ∑(u 取 i 的子节点)max(dp[u][0], dp[u][1])
代码:
void DP(int u, int p) {// p 为 u 的父节点
dp[u][] = ;
dp[u][] = ;
for(int k = head[u]; k != -; k = edge[k].next) {
int to = edge[k].to;
if(to == p) continue;
DP(to, u);
dp[u][] += dp[to][];
dp[u][] += max(dp[to][], dp[to][]);
}
}
参考文献《图论及应用》,以及部分网上的资料.
树形DP求树的最小支配集,最小点覆盖,最大独立集的更多相关文章
- HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...
- 浅谈关于树形dp求树的直径问题
在一个有n个节点,n-1条无向边的无向图中,求图中最远两个节点的距离,那么将这个图看做一棵无根树,要求的即是树的直径. 求树的直径主要有两种方法:树形dp和两次bfs/dfs,因为我太菜了不会写后者这 ...
- 树形DP求树的重心 --SGU 134
令一个点的属性值为:去除这个点以及与这个点相连的所有边后得到的连通分量的节点数的最大值. 则树的重心定义为:一个点,这个点的属性值在所有点中是最小的. SGU 134 即要找出所有的重心,并且找出重心 ...
- 树形dp - 求树的直径
随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好. 现在已经勘探确定了n个位置可 ...
- POJ 1655 Balancing Act (树形DP求树的重心)
题意: 求一棵树中以某个点为重心最小的子树集, 就是去掉这个点, 图中节点最多的联通块节点最少. 分析: 想知道这个点是不是最优的点, 只要比较它子树的数量和除去这部分其他的数量(它的父节点那部分树) ...
- 树形dp求树的重心
Balancing Act http://poj.org/problem?id=1655 #include<cstdio> #include<cstring> #include ...
- 树形DP求树的直径
hdu4607 Park Visit Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 树形DP 学习笔记(树形DP、树的直径、树的重心)
前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...
- 求树的最大独立集,最小点覆盖,最小支配集 贪心and树形dp
目录 求树的最大独立集,最小点覆盖,最小支配集 三个定义 贪心解法 树形DP解法 (有任何问题欢迎留言或私聊&&欢迎交流讨论哦 求树的最大独立集,最小点覆盖,最小支配集 三个定义 最大 ...
随机推荐
- [bzoj4860] [BeiJing2017]树的难题
Description 给你一棵 n 个点的无根树.树上的每条边具有颜色. 一共有 m 种颜色,编号为 1 到 m.第 i 种颜色的权值为 ci.对于一条树上的简单路径,路径上经过的所有边按顺序组成一 ...
- bug 跟蚊子的相似之处
bug 跟蚊子的相似之处: 1.不知道藏在哪里. 2.不知道有多少. 3.总是在你即将睡觉休息的时候出现. 2 A:最近在看<一拳超人>,觉得咱们程序猿跟埼玉老师有点像啊! B:哪里像了? ...
- POJ 3801/HDU 3157 Crazy Circuits | 有下界的最小流
题目: POJ最近总是炸 所以还是用HDU吧http://acm.hdu.edu.cn/showproblem.php?pid=3157 题解: 题很长,但其实就是给个有源汇带下界网络流(+是源,-是 ...
- C&C++——基本说明
预处理器(Preprocessor) 1 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS_PER_YEAR (60 * 60 * ...
- bzoj 1076 状压DP
我们设w[i][s]为当前到第i关,手中的物品为s的时候,期望得分为多少,其中s为二进制表示每种物品是否存在. 那么就比较容易转移了w[i][s]=(w[i-1][s']+v[j]) *(1/k),其 ...
- stdafx.h、stdafx.cpp的作用
这两个文件用于建立一个预编译的头文件".PCH"和一个预定义的类型文件"STDAFX.OBJ".由于MFC体系结构非常大,各个源文件中都包含许多头文件,如果每次 ...
- js事件中绑定另一事件导致事件多次执行
1.html代码 <input type="button" value="add"> <input type="button&quo ...
- UpdateData的用法(转)
原文转自 https://blog.csdn.net/ddjj_1980/article/details/51452289 UpdateData(TRUE)——刷新控件的值到对应的变量.(外部输入值交 ...
- CentOS 7 单用户模式修改root密码
1)在启动grub菜单,选择编辑选项启动 2)按键盘e键,来进入编辑界面 3)找到Linux 16的那一行,将ro改为rw init=/sysroot/bin/sh 4)现在按下Control+x,使 ...
- 如何开启SUSE Linux的SSH
1. 使用命令行停止防火墙 /etc/init.d/SuSEfirewall2_init stop /etc/init.d/SuSEfirewall2_setup stop 2. 修改 vi /etc ...