树形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];
    }
}
时间: 2024-08-06 16:06:07

树形DP 树的最小支配集,最小点覆盖与最大独立集的相关文章

贪心法求树的最小支配集,最小点覆盖,最大独立集

定义: 最小支配集:对于图G = (V, E) 来说,最小支配集指的是从 V 中取尽量少的点组成一个集合, 使得 V 中剩余的点都与取出来的点有边相连.也就是说,设 V' 是图的一个支配集,则对于图中的任意一个顶点 u ,要么属于集合 V', 要么与 V' 中的顶点相邻. 在 V' 中除去任何元素后 V' 不再是支配集, 则支配集 V' 是极小支配集.称G 的所有支配集中顶点个数最少的支配集为最小支配集,最小支配集中的顶点个数称为支配数. 最小点覆盖:对于图G = (V, E) 来说,最小点覆盖

树的最小支配集 最小点覆盖 与 最大独立集 (图论)

做 战略游戏 这道题的时候看到了这个东西,于是就来这里写了一下. 首先看一下三者的定义: 定义1 对于图G=(V,E)来说,最小支配集指的是从V中取尽量少的点组成一个集合,使得对于V中剩余的点都与取出来的点有边相连.也就是说,设V‘是图G的一个支配集,则对于图中的任意一个顶点u,要么属于集合V’,要么与V‘中的顶点相邻.在V’中出去任何元素后V‘不再是支配集,则支配集是极小支配集.称G的所有支配集中顶点个数最少的支配集为最小支配集,最小支配集中顶点的个数称为支配数. 定义2 对于图G=(V,E)

【POJ3659】【USACO 2008 Jan Gold】 3.Cell Phone Network 树上最小支配集/贪心 两种做法

题意:求树上最小支配集 最小支配集:点集,即每个点可以"支配"到相邻点,求最少点数可以使所有点被支配. 图上的最小支配集是NP的,但是树上的可以DP做,是O(n)的. 暴力做就好了, f[i]表示此 点被选时的子树全支配的最小代价 g[i]表示其父亲节 点被选时的子树全支配的最小代价 h[i]表示其某子节 点被选时的子树全支配的最小代价 然后暴力转移. (v是子节点) f[x]=∑(min(f[v],min(g[v],h[v])))+1; g[x]=∑(min(f[v],h[v]));

poj3659 Cell Phone Network(最小支配集-树形dp)

题目链接:点击打开链接 题目描述:给定一棵树,从中选取尽量少的点使每个点要么被选中,要么和被选中的点直接相连? 解题思路:树上的最小支配集,树形dp dp[i][0]:选中i作为支配集 dp[i][1]:不选i作为支配集,但其子节点覆盖了i dp[i][2]:不选i作为支配集,而且其子节点没有覆盖i 代码: #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include &l

POJ3659 Cell Phone Network(树上最小支配集:树型DP)

题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. 树上的每个结点作为其子树的根可以有三个状态: 不属于支配集且还没被支配 不属于支配集但被其孩子支配 属于支配集 那么就是用dp[u][1\2\3]来表示动归的状态. 123转移该怎么转移就怎么转移..最后的结果就是min(dp[root][2],dp[root][3]). 要注意的是对于有些结点前2

树的最小支配集,最小点覆盖,最大独立集两种算法

1.基本概念 对图G=<V,E>, 最小支配集:从V中取尽量少的点组成一个集合,使得V中剩余的点都与取出来的点有边相连 最小点覆盖:从V中取尽量少的点组成一个集合,使得E中所有边都与取出来的点相连 最大独立集:从V中取尽量多的点组成一个集合,使得这些点之间没有边相连 2.贪心法求树的最小支配集,最小点覆盖,最大独立集模板 基本算法: 以最小支配集为例,首先选择一点为根,按照深度优先遍历得到遍历序列,按照所得序列的反向序列的顺序进行贪心,对于一个既不属于支配集也不与支配集中的点相连的点来说,如果

[UVA-1218] Perfect Service(树的最小支配集)

题目链接:https://vjudge.net/problem/UVA-1218 题目大意:给你一棵无向树,让你求树的最小支配集,但是有一个要求是除最小支配集外剩下的任何一个结点不能同时连接支配集中的两个元素 解题报告:采用树形dp,只需将第一种状态的状态转移方程修改为$dp[i][0] = 1+\sum_{ p[u]=i }min(dp[u][0],dp[u][2])$ AC代码: 1 #include<vector> 2 #include<cstdio> 3 #include&

POJ 3659 Cell Phone Network(树的最小支配集)(贪心)

Cell Phone Network Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6781   Accepted: 2429 Description Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires hi

树的问题小结(最小生成树、次小生成树、最小树形图、LCA、最小支配集、最小点覆盖、最大独立集)

树的定义:连通无回路的无向图是一棵树. 有关树的问题: 1.最小生成树. 2.次小生成树. 3.有向图的最小树形图. 4.LCA(树上两点的最近公共祖先). 5.树的最小支配集.最小点覆盖.最大独立集. 一.最小生成树 解决的问题是:求无向图中边权值之和最小的生成树. 算法有Kruskal和Prim. Kruskal使用前向星和并查集实现,可以存储重边(平行边),时间复杂度是O(m log m  +  m),m是边的数量. Prim使用邻接矩阵建图,不可以存储重边(平行边),如果出现重边,存储的