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

1.基本概念

对图G=<V,E>,

最小支配集:从V中取尽量少的点组成一个集合,使得V中剩余的点都与取出来的点有边相连

最小点覆盖:从V中取尽量少的点组成一个集合,使得E中所有边都与取出来的点相连

最大独立集:从V中取尽量多的点组成一个集合,使得这些点之间没有边相连

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

基本算法:

以最小支配集为例,首先选择一点为根,按照深度优先遍历得到遍历序列,按照所得序列的反向序列的顺序进行贪心,对于一个既不属于支配集也不与支配集中的点相连的点来说,如果他的父节点不属于支配集,将其父节点加入支配集。


struct Edge
{
int v,next;
}G[M];

int fa[N];
int vis[N];
int pos[N],head[N];
int now;
int n,m;

void DFS(int u)
{
pos[now++] = u;
for(int i=head[u];i!=-1;i=G[i].next)
{
int v = G[i].v;
if(!vis[v])

{
vis[v] = 1;
fa[v] = u;
DFS(v);
}
}
}

int MDS()
{
int s[N] = {0};
int set[N] = {0};
int ans = 0;
for(int i=now-1;i>=0;i--)
{
int t = pos[i];
if(!s[t])
{
if(!set[fa[t]])
{
set[fa[t]] = 1;
ans++;
}
s[t] = 1;
s[fa[t]] = 1;
s[fa[fa[t]]] = 1;
}
}
return ans;
}

最小支配集MDS

int MPC()
{
int s[N] = {0};
int set[N] = {0};
int ans = 0;
for(int i=now-1;i>=0;i--)
{
int t = pos[i];
if(!s[t] && !s[fa[t]])
{
set[fa[t]] = 1;
ans++;
s[t] = 1;
s[fa[t]] = 1;
}
}
return ans;
}

最小点覆盖MPC

int MIS()
{
int s[N] = {0};
int set[N] = {0};
int ans = 0;
for(int i=now-1;i>=0;i--)
{
int t = pos[i];
if(!s[t])
{
set[t] = 1;
ans++;
s[t] = 1;
s[fa[t]] = 1;
}
}
return ans;
}

最大独立集MIS


int main()
{
//读入图信息
memset(vis,0,sizeof(vis));
now = 0;
vis[1] = 1;
fa[1] = 1;
DFS(1);
printf("%d\n",MIS()); //MDS | MPC
return 0;
}

3.树形DP算法

(1)最小支配集:

定义:

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

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

dp[i][2]: 点i不属于支配集,且以i为根的子树都被覆盖,且i没被子节点覆盖的情况下支配集包含的最少点数

则有:

dp[i][0] = SUM{min(dp[u][0],dp[u][1],dp[u][2])} (fa[u] = i)

dp[i][1]:

if(i没有子节点)  dp[i][1] = INF

else   dp[i][1] = SUM{min(dp[u][0],dp[u][1])} + inc  (fa[u] =
i)

inc有:

if(上面式子中SUM{min(dp[u][0],dp[u][1])}包含某个dp[u][0])  inc = 0

else  inc = MIN(dp[u][0]-dp[u][1]) (fa[u] = i)

dp[i][2] = SUM(dp[u][1]) (fa[u] = i)

void MDS_DP(int u,int fa)
{
dp[u][2] = 0;
dp[u][0] = 1;
int s = 0;
int sum = 0;
int inc = Mod;
for(int i=head[u];i!=-1;i=G[i].next)
{
int v = G[i].v;
if(v == fa)
continue;
MDS_DP(v,u);
dp[u][0] += min(dp[v][0],min(dp[v][1],dp[v][2]));
if(dp[v][0] <= dp[v][1])
{
sum += dp[v][0];
s = 1;
}
else
{
sum += dp[v][1];
inc = min(inc,dp[v][0]-dp[v][1]);
}
if(dp[v][1] != Mod && dp[u][2] != Mod)
dp[u][2] += dp[v][1];
else
dp[u][2] = Mod;
if(inc == Mod && !s) //i没有子节点
dp[u][1] = Mod;
else
{
dp[u][1] = sum;
if(!s)
dp[u][1] += inc;
}
}
}

最小支配集MDS_DP

(2)最小点覆盖

定义:

dp[i][0]: 点i属于点覆盖,并且以点i为根的自述中所连接的边都被覆盖的情况下点覆盖集所包含的最少点数

dp[i][1]: 点i不属于点覆盖,并且以点i为根的自述中所连接的边都被覆盖的情况下点覆盖集所包含的最少点数

则有:

dp[i][0] = SUM{min(dp[u][0],dp[u][1])}+1 (fa[u] = i)

dp[i][1] = SUM(dp[u][0])  (fa[u] = i)

void MPC_DP(int u,int fa)
{
dp[u][0] = 1;
dp[u][1] = 0;
for(int i=head[u];i!=-1;i=G[i].next)
{
int v = G[i].next;
if(v = fa)
continue;
MPC_DP(v,u);
dp[u][0] += min(dp[v][0],dp[v][1]);
dp[u][1] += dp[v][0];
}
}

最小点覆盖MPC_DP

(3)最大独立集

dp[i][0]: 点i属于独立集的情况下,最大独立集中点的个数

dp[i][1]: 点i属于独立集的情况下,最大独立集中点的个数

则有:

dp[i][0] = SUM(dp[u][1])+1  (fa[u] = i)

dp[i][1] = SUM{max(dp[u][0],dp[u][1])}  (fa[u] = i)

void MIS_DP(int u,int fa)
{
dp[u][0] = 1;
dp[u][1] = 0;
for(int i=head[u];i!=-1;i=G[i].next)
{
int v = G[i].v;
if(v == fa)
continue;
MIS_DP(v,u);
dp[u][0] += dp[v][1];
dp[u][1] += max(dp[v][0],dp[v][1]);
}
}

最大独立集MIS_DP

例题:POJ 3398 http://www.cnblogs.com/whatbeg/p/3776753.html

时间: 2024-08-02 21:59:27

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

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

定义: 最小支配集:对于图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.以1号点深度优先搜索整棵树,求出每个点在DFS中的编号和每个点的父亲节点编号. 2.按DFS的反向序列检查,如果当前点既不属于支配集也不与支配集中的点相连,且它的父亲也不属于支配集,将其父亲点加入支配集,支配集个数加1. 3.标记当前结点.当前结点的父节点(属于支配集).当前结点的父节点的父节点(与支配集中的点相连). #include<ios

树形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&