zoukankan      html  css  js  c++  java
  • 树形DP 树的最小支配集,最小点覆盖与最大独立集

    最小支配集:

    从V中选取尽量少的点组成一个集合,让V中剩余的点都与取出来的点有边相连。

    (点)

    最小点覆盖:

    从V中选取尽量少的点组成一个集合V1,让所有边(u,v)中要么u属于V1,要么v属于V1

    (边)

    最大独立集:

    从V中选取尽量多的点组成一个集合,让这些点中间没有边项链,也就是说对于任何一条边,u,v不能同时属于集合V1.

    1.贪心算法

    首先选取一个点为根节点,求出所有节点对应的DFS序列,按照所得序列反向进行贪心,这样保证对于每个点来说,当子树都被处理过之后才会处理该节点

    int p[MAXN];
    bool select[MAXN];
    int newpos[MAXN];
    int now, n, m;
    //最小支配集
    int greedy1()
    {
        bool s[MAXN] = { 0 };
        bool set[MAXN] = { 0 };
        int ans = 0;
        int i;
        for (i = n - 1; i >= 0; i--)
        {
            int t = newpos[p[t]];
            if (!s[t])
            {
                if (!set[p[t]])
                {
                    set[p[t]] = true;
                    ans++;
                }
                s[t] = s[p[t]] = s[p[p[t]]] = true;
            }
        }
        return ans;
    }
    //最小点覆盖
    int greedy2()
    {
        bool s[MAXN] = { 0 };
        bool set[MAXN] = { 0 };
        int ans = 0;
        for (int i = n - 1; i >= 1; i--)//不可以检查根节点,p[root] = root
        {
            int t = newpos[i];
            if (!s[t] && !s[p[t]])
            {
                set[p[t]] = true;
                ans++;
                s[t] = s[p[t]] = true;
            }
        }
    }
    //最大独立集
    int greedy3()
    {
        int ans = 0;
        bool s[MAXN] = { 0 };
        bool set[MAXN] = { 0 };
        for (int i = 1; i >= 0; i--)
        {
            int t = newpos[i];
            if (!s[t])
            {
                set[t] = true;
                ans++;
                s[t] = s[p[t]] = true;
            }
        }
        return ans;
    }

    2.树形DP

    1.dp[i][0]: 表示点i属于支配集,并且以点i为根的子树都被覆盖了的情况下支配集中包含点最少的个数

    2.dp[i][1] i不属于支配集,而且以i为根的子树都被覆盖而且i被其中不少于一个子节点覆盖情况下支配集所包含最少点的个数

    3.dp[i][2] i不属于支配集,而且i为根的子树都被覆盖而且I没有被子节点覆盖的情况下支配集报验最少点的个数

    对于第一情况,对子节点无限制

    dp[i][0] = 1 + 西格玛min(dp[u][0],dp[u][1],dp[u][2]) p[u] = t

    对于第二红情况, 如果i没有子节点那么dp[i][1] = INF,子节点必须被覆盖,所以和状态dp[i][2]无关的!

    dp[i][1] = 西格玛min(dp[u][0],dp[u][1]) + inc

    如果选取了某一个dp[u][0] inc = 0;

    else inc = min(dp[u][0] - dp[u][1])

    选取的时候注意如果全部选的都是dp[u][1]那父节点没办法被覆盖啦!所以判断一下

    对于第三种情况,i不属于支配集,i的子树都被覆盖,说明i和i的儿子都不是支配集的!

    dp[i][2] = 西格玛dp[u][1]

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<functional>
    #include<fstream>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    #define N 31
    #define INF 1000000009
    #define eps 0.00000001
    #define sf(a) scanf("%d",&a)
    const int MAXN = 1e5 + 3;
    
    int dp[MAXN][3];
    int head[MAXN];
    void DP(int u, int p)
    {
        dp[u][2] = 0;
        dp[u][0] = 1;
        bool s = false;
        int sum = 0, inc = INF;
        int k;
        for (k = head[u]; k != -1; k = E[k].next)
        {
            int to = E[k].to;
            if (to == p)
                continue;
            DP(to, u);
            dp[u][0] += min(dp[to][0], dp[to][1], dp[to][2]);
            if (dp[to][0] < dp[to][1])
            {
                s = true;
                sum += dp[to][0];
            }
            else
            {
                sum += dp[to][1];
                inc = min(inc, dp[to][0] - dp[to][1]);
            }
            if (dp[to][1] != INF&&dp[u][2] != INF)
                dp[u][2] += dp[to][1];
            else
                dp[u][2] = INF;
        }
        if (inc == INF && !s)
            dp[u][1] = INF;
        else
        {
            dp[u][1] = sum;
            if (!s) dp[u][1] += inc;
        }
    }

    对于最小点覆盖

    dp[u][0] u点被覆盖

    dp[u][1] u点没被覆盖

    int dp[MAXN][3];
    int head[MAXN];
    void DP(int u, int p)
    {
        dp[u][0] = 1;
        dp[u][1] = 0;
        int k, to;
        for (k = head[u]; k != -1; k = E[k].next)
        {
            to = E[k].to;
            if (to == p)
                continue;
            DP(to, u);
            dp[u][0] += min(dp[to][0], dp[to][1]);
            dp[u][1] += dp[to][0];
        }
    }
  • 相关阅读:
    开发人员的幽默
    SpaceBuilder 1.0RC源代码提供下载
    什么是Alpha,Beta,RC,RTM版
    SQLite数据库参数化编程时,采用命名参数的方式
    ASP.NET第四天数据库知识
    ASP.NET第五天数据库知识
    ASP.NET第五天HTML基础
    ASP.NET第二天HTML基础
    ASP.NET第四天HTML基础
    ASP.NET第一天HTML基础
  • 原文地址:https://www.cnblogs.com/joeylee97/p/7488710.html
Copyright © 2011-2022 走看看