树形DP—最小支配集

最小支配集:对于图G=<V,E>,从V中取尽量少的点组成一个集合,使得V中剩余的点都与取出来的点有边相连
考虑到最小支配集,每个点都有两种状态,即属于支配集合或者是不属于支配集合,其中不属于支配集合时此点还需要被覆盖,被覆盖也有两种状态,即被子节点覆盖或者被父节点覆盖。总结起来就是三种状态,即:

  1. dp[i][1],表示点 i 属于支配集合,并且以点 i 为根的子树都覆盖了的情况下支配集中所包含最少点的个数
  2. 对于第一种状态,dp[i][1]含义为点 i 属于支配集合,那么依次取每个儿子节点三种状态中的最小值,再把取得的最小值全部加起来再加 1,就是dp[i][1]的值了.即只要每个以 i 的儿子为根的子树都被覆盖,再加上当前点 i,所需要的最少的点的个数,DP转移方程如下:
    dp[i][1] = 1 + ∑(u取i的子节点)min(dp[u][0], dp[u][1], dp[u][2])
  3. dp[i][0],表示点 i 不属于支配集,且以 i 为根的子树都被覆盖,且 i 被其中不小于一个子节点覆盖的情况下支配集所包含最少点的个数。
  4. 对于第二种状态,略有些复杂.首先如果点 i 没有子节点那么 dp[i][0]应该初始化为 INF;否则为了保证它的每个以 i 的儿子为根的子树被覆盖,那么要取每个儿子节点的前两种状态的最小值之和,因为此时点 i 不属于支配集,不能支配其子节点,所以子节点必须已经被支配,与子节点的第三种状态无关.如果当前所选状态中每个儿子都没被选择进入支配集,即在每个儿子的前两种状态中,第一种状态都不是所需点最小的,那么为了满足第二种状态的定义(因为点 i 的第二种状态必须被其子节点覆盖,即其子节点必须有一个属于支配集,如果此时没有,就必须强制使一个子节点的状态为状态一),需要重新选择点 i 的一个儿子节点为第一种状态,这时取花费最少的一个点,即取min(dp[u][0] - dp[u][1])的儿子节点 u,强制取其第一种状态,其他的儿子节点取第二种状态,DP转移方程为:
    if(i 没有子节点) dp[i][0] = INF
    else dp[i][0] = ∑(u取i的子节点)min(dp[u][0], dp[u][1]) + inc
    其中对于 inc 有:
    if(上面式子中的 ∑(u取i的子节点)min(dp[u][0], dp[u][1]) 中包含某个 dp[u][1], 即存在一个所选的最小值为状态一的儿子节点) inc = 0
    else inc = min(dp[u][1] - dp[u][0]) (其中 u 取点 i 的儿子节点)
  5. dp[i][2],表示点 i 不属于支配集,且以 i 为根的子树都被覆盖,且 i 没被子节点覆盖的情况下支配集所包含最少点的个数。
  6. 对于第三种状态,dp[i][2]含义为点 i 不属于支配集合,且 i 被其父节点覆盖.那么说明点 i 和点 i 的儿子节点都不属于支配集合,所以点 i 的第三种状态之和其儿子节点的第二种状态有关,方程为:
    dp[i][2] = ∑(u取i的子节点)dp[u][0]
void DP(int u, int p) {// p 为 u 的父节点
    dp[u][2] = 0;
    dp[u][1] = 1;
    bool s = false;
    int sum = 0, inc = INF;
    for(int k = head[u]; k != -1; k = edge[k].next) {
        int to = edge[k].to;
        if(to == p) continue;
        DP(to, u);
        dp[u][1] += min(dp[to][1], min(dp[to][0], dp[to][2]));
        if(dp[to][1] <= dp[to][0]) {
            sum += dp[to][1];
            s = true;
        }
        else {
            sum += dp[to][0];
            inc = min(inc, dp[to][1] - dp[to][0]);
        }
        if(dp[to][0] != INF && dp[u][2] != INF) dp[u][2] += dp[to][0];
        else dp[u][2] = INF;
    }
    if(inc == INF && !s) dp[u][0] = INF;
    else {
        dp[u][0] = sum;
        if(!s) dp[u][0] += inc;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逃夭丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值