树的最小支配集、最小点覆盖、最大独立集【模板】

最小支配集:指从所有顶点中取尽量少的点组成一个集合,使得剩下的所有点都与取出来的点有边相连。顶点个数最小的支配集被称为最小支配集。这里用贪心法来求。

1.以1号点深度优先搜索整棵树,求出每个点在DFS中的编号和每个点的父亲节点编号。

2.按DFS的反向序列检查,如果当前点既不属于支配集也不与支配集中的点相连,且它的父亲也不属于支配集,将其父亲点加入支配集,支配集个数加1。

3.标记当前结点、当前结点的父节点(属于支配集)、当前结点的父节点的父节点(与支配集中的点相连)。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 20020;

struct EdgeNode
{
    int to;
    int next;
}Edges[MAXN];
int Head[MAXN],father[MAXN],NewPos[MAXN];
bool vis[MAXN];
//NewPos[]表示深度优先遍历序列的第i个点是哪个点
//now表示当前深度优先遍历序列中已经有多少个点了
//vis[]用来深度优先遍历的判重
//father[]表示点i的父亲节点编号
int N,M,now;
void DFS(int x)   //得到深度优先队列的反向序列
{
    NewPos[now++] = x;
    for(int k = Head[x]; k != -1; k = Edges[k].next)
    {
        if(!vis[Edges[k].to])
        {
            vis[Edges[k].to] = true;
            father[Edges[k].to] = x;
            DFS(Edges[k].to);
        }
    }
}

//S[i]为true,表示第i个点被覆盖了
//Set[i]表示点i属于要求的点集
bool S[MAXN],Set[MAXN];
int Greedy()//贪心求最小支配集
{
    memset(S,0,sizeof(S));
    memset(Set,0,sizeof(Set));
    int ans = 0;
    for(int i = N-1; i >= 1; i--)//反向序列检查
    {
        int t = NewPos[i];
        if(!S[t])//当前点未被覆盖,也就是当前点既不属于支配集,也不与支配集中的点相连
        {
            if(!Set[father[t]])//当前点的父亲结点不属于支配集,
            {
                Set[father[t]] = true;  //将父节点加入支配集
                ans++;                  //顶点个数加1
            }
            S[t] = true;
            S[father[t]] = true;
            S[father[father[t]]] = true;
            //标记当前点、当前结点的父节点、当前结点的父节点的父节点
        }
    }
    return ans;
}

int main()
{
    int u,v;
    while(~scanf("%d",&N))
    {   //初始化
        memset(Edges,0,sizeof(Edges));
        memset(Head,-1,sizeof(Head));
        memset(father,0,sizeof(father));
        memset(vis,false,sizeof(vis));
        memset(NewPos,0,sizeof(NewPos));
        int id = 0;
        for(int i = 0; i < N-1; ++i)
        {
            scanf("%d%d",&u,&v);
            Edges[id].to = v;
            Edges[id].next = Head[u];
            Head[u] = id++;
            Edges[id].to = u;
            Edges[id].next = Head[v];
            Head[v] = id++;
        }
        now = 0;
        vis[1] = true;
        father[1] = 1;
        DFS(1);
        printf("%d\n",Greedy());
    }

    return 0;
}

最小点覆盖:指从所有顶点中取尽量少的点组成一个集合,使得集合中所有的边都与取出来的点有边相连。顶点个数最小的覆盖集被称为最小点覆盖。

贪心策略:如果当前点和当前点的父节点都不属于顶点覆盖集合,则将父节点加入到顶点覆盖集合中,并标记当前节点和其父节点都被覆盖。

int Greedy()//贪心求最小点覆盖
{
    memset(S,0,sizeof(S));
    memset(Set,0,sizeof(Set));
    int ans = 0;
    for(int i = N-1; i >= 1; i--)//反向序列检查
    {
        int t = NewPos[i];
        if(!S[t] && !S[father[t]])//当前点和当前点的父节点都不属于顶点覆盖集合
        {
            Set[father[t]] = true;  //当前点的父节点加入到顶点覆盖集合中
            ans++;                  //顶点个数+1
            S[t] = true;
            S[father[t]] = true;
            //标记当前点、当前结点的父节点
        }
    }
    return ans;
}

最大独立集:指从所有顶点中取尽量多的点组成一个集合,使得这些点之间没有边相连。顶点个数最多的独立集被称为最大独立集。

贪心策略:如果当前节点没有被覆盖,则将当前节点加入独立集,并标记当前节点和其父节点都被覆盖。

int Greedy()//贪心求最大独立集
{
    memset(S,0,sizeof(S));
    memset(Set,0,sizeof(Set));
    int ans = 0;
    for(int i = N-1; i >= 1; i--)//反向序列检查
    {
        int t = NewPos[i];
        if(!S[t])//当前点未被覆盖
        {

            Set[t] = true;  //将当前点加入独立集
            ans++;                  //独立集点个数加1

            S[t] = true;
            S[father[t]] = true;
            //标记当前点、当前结点的父节点都被覆盖
        }
    }
    return ans;
}
时间: 2024-11-05 11:51:54

树的最小支配集、最小点覆盖、最大独立集【模板】的相关文章

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

定义: 最小支配集:对于图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]));

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

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

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

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

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

最小支配集: 从V中选取尽量少的点组成一个集合,让V中剩余的点都与取出来的点有边相连. (点) 最小点覆盖: 从V中选取尽量少的点组成一个集合V1,让所有边(u,v)中要么u属于V1,要么v属于V1 (边) 最大独立集: 从V中选取尽量多的点组成一个集合,让这些点中间没有边项链,也就是说对于任何一条边,u,v不能同时属于集合V1. 1.贪心算法 首先选取一个点为根节点,求出所有节点对应的DFS序列,按照所得序列反向进行贪心,这样保证对于每个点来说,当子树都被处理过之后才会处理该节点 int p[

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

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

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

[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&