一:最小支配集

考虑最小支配集,每个点有两种状态,即属于支配集合或者不属于支配集合,其中不属于支配集合时此点还需要被覆盖,被覆盖也有两种状态,即被子节点覆盖或者被父节点覆盖.总结起来就是三种状态,现对这三种状态定义如下:

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求树的最小支配集,最小点覆盖,最大独立集的更多相关文章

  1. HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

  2. 浅谈关于树形dp求树的直径问题

    在一个有n个节点,n-1条无向边的无向图中,求图中最远两个节点的距离,那么将这个图看做一棵无根树,要求的即是树的直径. 求树的直径主要有两种方法:树形dp和两次bfs/dfs,因为我太菜了不会写后者这 ...

  3. 树形DP求树的重心 --SGU 134

    令一个点的属性值为:去除这个点以及与这个点相连的所有边后得到的连通分量的节点数的最大值. 则树的重心定义为:一个点,这个点的属性值在所有点中是最小的. SGU 134 即要找出所有的重心,并且找出重心 ...

  4. 树形dp - 求树的直径

    随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好. 现在已经勘探确定了n个位置可 ...

  5. POJ 1655 Balancing Act (树形DP求树的重心)

    题意: 求一棵树中以某个点为重心最小的子树集, 就是去掉这个点, 图中节点最多的联通块节点最少. 分析: 想知道这个点是不是最优的点, 只要比较它子树的数量和除去这部分其他的数量(它的父节点那部分树) ...

  6. 树形dp求树的重心

    Balancing Act http://poj.org/problem?id=1655 #include<cstdio> #include<cstring> #include ...

  7. 树形DP求树的直径

    hdu4607 Park Visit Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  8. 树形DP 学习笔记(树形DP、树的直径、树的重心)

    前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...

  9. 求树的最大独立集,最小点覆盖,最小支配集 贪心and树形dp

    目录 求树的最大独立集,最小点覆盖,最小支配集 三个定义 贪心解法 树形DP解法 (有任何问题欢迎留言或私聊&&欢迎交流讨论哦 求树的最大独立集,最小点覆盖,最小支配集 三个定义 最大 ...

随机推荐

  1. TCP/IP Note3

    TCP/IP协议 TCP/IP是不同的通信协议的大集合. 协议族:TCP/IP是基于TCP和IP这两个最初的协议之上的不同的通信协议的大集合. 1. TCP - 传输控制协议 TCP用于从应用程序到网 ...

  2. 周记【距gdoi:91天】

    这星期挺没状态的.听蔡大神讲组合游戏,然后欢乐得以为自己懂了,然后看到题目就懵了,然后就各种乱各种走神……但是某大神们(kpm和child)疯狂地切题.然后又颓废了两个晚上后决定滚回去文化课(oi没状 ...

  3. 【BZOJ3887】【Usaco2015 Jan】Grass Cownoisseur Tarjan+Spfa

    我们可以看出这个东西可以缩点成DAG,因为我们在所称的点里用特技的话,要么没用,要么削弱自己对点的收割能力与边的联通权,所以我们缩完点之后在图上枚举反向的变,因为我们只可能反向一条边,而且我们知道在这 ...

  4. NAS星云链 入门之从零开发第一个DAPP

    应该有很多小伙伴和我一样,一直想去入手学习区块链,但是总无从下手,有些概念感觉理解了,有感觉没理解.其实这都是“没实践”的锅. 所谓看十遍不如想一遍,想一遍不如做一遍.这不最近星云链nebulas正有 ...

  5. 自己模拟实现一下Google的赛马Doodle

    今天的Google Doodle是个动态的,是一个骑马的动态Doodle,是谷歌纪念英国实验摄影师埃德沃德·迈布里奇182周年诞辰,埃德沃德·迈布里奇是运动摄影的开创者,所以谷歌涂鸦以一个运动的摄影作 ...

  6. ng父组件调用子组件的方法

    https://www.pocketdigi.com/20170204/1556.html 组件之间方法的调用统一用中间人调用.数据传递直接input和output即可

  7. How to setup Active Directory (AD) In Windows Server 2016

    Windows Server 2016 is the newest server operating system released by Microsoft in October 12th, 201 ...

  8. MyBatis+Spring实现基本CRUD操作

    一.MyBaits介绍   MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的JDBC代码.手工设置参数和结果集重获.MyBatis 只使用简单的X ...

  9. Spring - IoC(9): @Resoure & @Autowired

    @Resource 和 @Autowired 都是用来装配依赖的,它们之间有些异同. @Resoure @Resource 是 JSR-250 规范的注解. @Resource 可以标注在字段.方法上 ...

  10. AQS同步组件及ReentrantLock和synchronized的区别

    AQS同步组件 CountDownLatch(只有一个线程对他进行操作): 主线程必须在启动其它线程后立即调用await()方法.这样主线程的操作就会在这个方法上阻塞,直到其它线程完成各自的任务. S ...