树形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解法 (有任何问题欢迎留言或私聊&&欢迎交流讨论哦 求树的最大独立集,最小点覆盖,最小支配集 三个定义 最大 ...
随机推荐
- WebSocket对象的创建及其与WebSocket服务器的连接(5)
WebSocket接口的使用非常简单,要连接通信端点,只需要创建一个新的WebSocket实例,并提供希望连接URL. //ws://和wss://前缀分别表示WebSocket连接和安全的WebSo ...
- 【题解】HEOI2013Eden 的新背包问题
这题真的神奇了……蜜汁复杂度(`・ω・´) 应该是一个比较连贯的思维方式:去掉一个物品,那么我们转移的时候不考虑它就好了呗.考虑暴力:每一次都对剩余的n - 1个物品进行多重背包转移,获得答案.既然可 ...
- 安徽师大附中%你赛day4T2 演讲解题报告
演讲 题目背景: 众所周知,\(\mathrm{Zdrcl}\)是一名天天\(\mathrm{AK}\)的高水平选手. 作为一民长者,为了向大家讲述自己\(\mathrm{AK}\)的经验,他决定在一 ...
- 获取本地ip地址 C#
与ipconfig获取的所有信息一致的方法: private void GetIp() { System.Diagnostics.Process cmdp= new System.Diagnostic ...
- 如何使用Navicat备份数据库脚本
Navicat是一个实用的工具,可以用来备份数据库(Oracle.MySQL.SQLServer)脚本. 备份步骤如下: 1.打开已建立的数据库连接,鼠标右键点击,选择[转储SQL文件]->[结 ...
- 把java的class文件打成jar包的步骤
现在我的文件夹的目录在: C:\Users\linsenq\Desktop\cglibjar 我要把位于这个目录下的所有文件夹以及这个文件夹下的.class文件打成jar包 第一步:用win+R 打开 ...
- POJ 1062 昂贵的聘礼 (最短路 迪杰斯特拉 )
题目链接 Description 年轻的探险家来到了一个印第安部落里.在那里他和酋长的女儿相爱了,于是便向酋长去求亲.酋长要他用10000个金币作为聘礼才答应把女儿嫁给他.探险家拿不出这么多金币,便请 ...
- Ubuntu 15.10 安装比特币客户端
下载 git clone https://github.com/bitcoin/bitcoin.git cd bitcoin ./autogen.sh 安装依赖包: ++-dev sudo apt-g ...
- cobalt strike使用笔记
启动: ./teamserver 192.168.74.1 admin #启动cs服务器.admin为密码. 监听器: windows/beacon_dns/reverse_dns_txtwindow ...
- Django-urls路由分发
例如:127.0.0.0:8000/blog/lucaq.html,当有多个应用时,需要在blog应用下进行路由,我们在blog应用下做一个urls路由分发,就需要include模块实现. 导 ...