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

首先看一下三者的定义:

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

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

定义3 对于图G=(V,E)来说, 最大独立集 指的是从V中取尽量多的点组成一个集合,使得这些点之间没有边相连。也就是说,设V’是图G的一个独立集,则对于图中任意一条边(u,v),u和v不能同时属于集合V',甚至可以u和v都不属于集合V‘。在V’中添加任何不属于V‘元素后V’不再是独立集,则V‘是极大独立集。称G的所有顶点独立集中顶点个数最多的独立集为最大独立集。

对于任意图G来说,这三个问题不存在多项式时间的解法。 不过对于树来说,却很容易。目前有两种解法,一种基于贪心思想,另一种基于树形动态规划思想。


求解(贪心算法):对整棵树进行dfs,求出dfs序,然后进行贪心。以求支配集为例,对于儿子和父亲,肯定选父亲能影响到的更多,那么只要把最小面一层确定后就可以从后往前进行判断了。


 1 int p[maxn];
 2 bool select[maxn];
 3 int newpos[maxn];
 4 int now;
 5 int n,m;
 6 void DFS(int x)
 7 {
 8     newpos[now++]=x;
 9     int k;
10     for(k=head[x];k!=-1;k=edge[k].next)
11     {
12         if(!select[edge[k].to])
13         {
14             select[edge[k].to]=true;
15             p[edge[k].to]=x;
16             DFS(edge[k].to);
17         }
18     }
19 }
View Code

对于最小支配集,贪心函数如下:

 1 int greedy()
 2 {
 3     bool s[maxn];
 4     bool set[maxn]={0};
 5     int ans=0;
 6     int i;
 7     for(i=n-1;i>=0;i--)
 8     {
 9         int t=newpos[i];
10         if(!s[t])
11         {
12             if(!set[p[t]])
13             {
14                 set[p[t]]=true;
15                 ans++;
16             }
17             s[t]=true;
18             s[p[t]]=true;
19             s[p[p[t]]]=true;
20         }
21     }
22     return ans;
23 }
View Code

对于最小点覆盖,贪心函数如下:

 1 int greedy()
 2 {
 3     bool s[maxn]={0};
 4     bool set[maxn]={0};
 5     int ans=0;
 6     int i;
 7     for(i=n-1;i>=1;i--)
 8     {
 9         int t=newpos[i];
10         if(!s[t]&&s[p[t]])
11         {
12             set[p[t]]=true;
13             ans++;
14             s[t]=true;
15             s[p[t]]=true;
16         }
17     }
18     return ans;
19 }
View Code

对于最大独立集,贪心函数如下:

 1 int greedy()
 2 {
 3     bool s[maxn]={0};
 4     bool set[maxn]={0};
 5     int ans=0;
 6     int i;
 7     for(i=n-1;i>=0;i--)
 8     {
 9         int t=newpos[i];
10         if(!s[t])
11         {
12             set[t]=true;
13             ans++;
14             s[t]=true;
15             s[p[t]]=true;
16         }
17     }
18     return ans;
19 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值