文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>有关独立集的算法

有关独立集的算法

时间:2010-09-19  来源:Creason New

关于独立集的问题有很多,比如地图填色问题、区域控制问题等。好多实际问题都可以抽象成独立集的问题,然后解决,比如对地图上的国家填充颜色,相邻的国家不能使用同一种颜色,这时就可以使用独立集求解。在上篇文章中《带权请求策略的几种算法》中,一种解法就使用了独立集的方法,下面我也会把具体的解法写出来。

问题描述

图G表示为,V为G的顶点集,E为G的边集,设顶点a属于独立集S,那么S中所有属于图G的顶点都没有边直接相连。


Figure 1.1 A independent set whose node colored gray in the graph

我们称上图中灰色节点为图的一个独立集。一般独立集的问题有求解图的独立集,求解图的最大独立集问题。

几种不同的独立集

一个图可以有多个独立集,每一个独立集都有一些特性,对他们归纳总结,我大致分一下几个类别:最大独立集、最小独立集、最多独立集、最少独立集、关联顶点独立集。

  • 最大独立集,这种独立集最为常见,就是图G的独立集中包含顶点最多的那一个独立集。
  • 最小独立集,顾名思意,相对于最大独立集来说,就是包含顶点最少的独立集,所以它没有研究意义,它包含的顶点数恒等于1
  • 最少独立集,设S为包含图G独立集的集合,也就是说S的元素都是图G的独立集,且S中元素包含的顶点=图G的顶点集V,当S的容量最小时,我们称S为G的最少独立集。在Scheduling All Intervals(多资源请求安排策略,多个请求使用同一资源,但时间有交叉,求提供最少的资源满足这些请求。)问题上,可以使用最少独立集的理论来解决,而不是贪心算法。
  • 最多独立集,相对于上面的最少独立集,它没有研究意义,最多独立集恒等于{{a},{b},……}
  • 关联顶点最大独立集,即包含顶点A的关于图G的独立集,有时候为了获得包含某顶点的独立集,我们不得不求出图全部的独立集,这很浪费资源,因此更好的策略是直接求关于某点的独立集。

求解几种不同独立集的算法

1.最少独立集求解算法

从上一节我们知道了最少独立集的概念,怎么求解图G的最少独立集呢?本方法我叫做验证法,下面是伪代码:

//初始化最少集S,当前独立集s1
S={};s1={V[0]};
S.Append(s1);
//遍历顶点集V
for(i=1;i<V.length;i++){
    //如果当前顶点与前面所有的独立集有边
    if(V[i]与S中的顶点有边){
        //初始化一个新的独立集
        ns={};
        ns.Append(V[i]);
        S.Append(ns);
    }
    else{
        //遍历S中的所有独立集
        for(i=0;i<S.length;i++)
            if(S[i]中所有的顶点与V[i]都没有边)
                S[i].Append(V[i]);break;
    }
}

其实本算法很简单,先把第一个顶点A加入到第一个独立集s1中,然后依次遍历每一个顶点,如果当前顶点与集合s1中的顶点有边,就新建一个独立集s2,并把当前顶点加入s2中,照此规则,最终生成的几个独立集将是最少独立集的解。
例如,对于Figure 1.1算法的执行情况是:

  • 第一步:    s1={A}, S={s1}
  • 遍历B顶点:    s1={A}, s2={B}, S={s1,s2}
  • 遍历C顶点:    s1={A}, s2={B,C}, S={s1,s2}
  • 遍历D顶点:    s1={A,D}, s2={B,C}, S={s1,s2}
  • 遍历E顶点:    s1={A,D}, s2={B,C}, s3={E} S={s1,s2,s3}
  • 遍历F顶点:    s1={A,D,F}, s2={B,C}, s3={E} S={s1,s2,s3}
  • 遍历G顶点:    s1={A,D,F}, s2={B,C,G}, s3={E} S={s1,s2,s3}
  • 遍历H顶点:    s1={A,D,F}, s2={B,C,G}, s3={E}, s4={H} S={s1,s2,s3,s4}
  • 遍历I顶点:    s1={A,D,F}, s2={B,C,G,I}, s3={E}, s4={H} S={s1,s2,s3,s4}

说到这里,我想大家都明白本算法是怎么回事了,非常简单不是吗?但是,这里有一个问题,就是通过这种算法形成的解中,会有一些独立集中顶点数量特别多,有些独立集的顶点数量又特别少,我称这种现象为“独立集失衡”,那么怎么生成一个较为“平衡”但又是最少的独立集呢?只需要做小小改进即可。

重新回到上面的算法,当一个顶点与当前解集S中没有边时,应该把该顶点加入S中的哪一个独立集中呢?s1,s2还是s3,这就是造就“独立集失衡”的罪魁祸首,上面的算法是始终从第一个独立集开始,如果当前顶点与该独立集没有边,就加入到该集中,也就是说,我们每一次都“关照”排名考前的独立集,好了,说到这里,解决“独立集失衡”问题的方法迎刃而解,我们增加一个计数器,记录最后添加顶点的独立集的索引,下一次向独立集添加顶点时从它的下家开始就OK了。下面是伪代码:

//初始化最少集S,当前独立集s1
S={};s1={V[0]};
S.Append(s1);
//失衡计数器
int count=0;
//遍历顶点集V
for(i=1;i<V.length;i++){
    //如果当前顶点与前面所有的独立集有边
    if(V[i]与S中的顶点有边){
        //初始化一个新的独立集
        ns={};
        ns.Append(V[i]);
        S.Append(ns);
    }
    else{
        //遍历S中的所有独立集
        for(i=0;i<S.length;i++){
            int index;
            if((count+i)>S.length)    index=i-count-1;
            else    index=i+count;
            if(S[index]中所有的顶点与V[i]都没有边){
                S[index].Append(V[i]);
                count++;
                break;
            }
        }
    }
}

以上算法的解为:s1={A,D,F}, s2={B,C,G}, s3={E,I}, s4={H}

2.关联顶点最大独立集求解算法

怎么求解包含某个顶点的最大独立集呢?我们当然可以用枚举法产生,因为我们是程序员,所以总会有更好的方法,就像万能的上帝,什么时候都不乏好的想法。

我们先思考一个最大的独立集所具有的特征,我们发现几乎所有的独立集中包含的顶点的“度”都不会太大。度,就是顶点的边数,对于有向图还有入度和出度的概念。假设,某个顶点的度很大,以至于它跟每一个顶点都有一条边,那么包含这个顶点的独立集绝对不会是最大独立集。基于这个想法,我们从顶点的度入手,运用贪心策略,我们每一步都尽量选择度数小的顶点作为最大独立集中的顶点。对于Figure 1.1中的图,它们的度为:


Figure 3.1 Degree of the graph

按照度数小优先的原则,我们可以生成一个包含某顶点的最大独立集。下面是伪代码:

//初始化独立集S和临时集
S={A};cur={};exploed={A}+f(A)
while(exploed!=V){
    //遍历S中“邻居”的“邻居”,即A外2层的节点,并加入cur集合中
    cur={x|x∈f(f(S))}    //f(x)函数表示与x集合中顶点有边的所有顶点
    exploed.Append(cur);
    //按照顶点的度对cur升序排序
    cur.Sort("ASC");
    //遍历cur中的顶点直到cur为空
    for(i=0;cur!=null;i++){
        S.Append(cur[i]);
        //删除cur中与cur[i]有边的顶点
        S.Delete(Disjoin(cur[i]));
    }
}

比如,我们求解包含A的最大独立集,下面是代码的执行过程:

  • 第一步:    cur={},exploed={A} S={A}
  • 第一次循环:    cur={F,G,H,D},exploed={A,F,G,H,D} S={A,F,H}
  • 第二次循环:    cur={I},exploed={A,F,G,H,D,I} S={A,F,H,I}
  • 终止:    exploed+f(A)=V    cur={},exploed={A,F,G,H,D,I} S={A,F,H,I}

在算法的执行过程中,临时集合cur是在不断变化的,本算法的执行效率与图的结构有关。我称这种算法为最小度优先加点法。对于大的图,它可能不会生成一个包含某顶点的最大独立集,但是可以近似的最大了,本算法的一些特性还有待研究,希望大家多不吝言辞。

最大独立集求解算法

在独立集的诸多问题中,最大独立集是最重要的也是最常用的一种独立集情形。怎么生成一个图的最大独立集呢?我这有三种算法,一种是网络上的算法,另外两种是我的见解。

1.最小覆盖集算法

图G(V,E)的覆盖集D是顶点集的一个子集,并满足:任意 <vi,vj>属于E,vi属于D或vj属于D  

定义 *,+ 满足交换率,结合率, 
且 *对+分配 (a+b)*c = a*c + b*c 
       
吸收率: 
a+ab = a 
a*a = a 
a+a = a 

这样,求极小覆盖集: 

 M(连乘)(  (v[i]  +  M(所有与v[i]相邻的点)   ) 
i=0 to n         

结果化简后的每个因子项即对应一个极小覆盖集。 

for example: 
a---b---c 
 \ / \ / 
  d   e 

(a+bd)(b+acde)(c+be)(d+ab)(e+bc) 
 = acde+abe+bcd+abc+bde   

acde,abe,bcd,abc,bde 既是G的各个极小覆盖集。 

因为极小覆盖集和极大独立集互补,用abcde 减去各个极小覆盖集, 
既得到极大独立集: 
b dc ae de ac  

其中dc ae de ac是最大独立集。 

2.动态规划法

动态规划算法的普适性很强,以至于什么问题我们都可以进行动态规划一下,但是对于某些问题,动态规划的效果却欠佳。
设P(x)为包含x的最大独立集,L(x)为x的相邻顶点。那么有:

P(x)=x+max(P(y))    y∈{V-x-L(x)}

有了上面的公式,算法便一目了然了。同样,这种方法还适用于关联顶点的独立集问题。它的效率实在太低了,所以大家就不要用了。

3.最大度优先减点法

在上面的关联顶点独立集的问题中我提到了一种算法,叫最小度优先加点法,原理是一样的,对于求最大独立集的问题,我们首先找到度数最大的顶点,然后删除它,直到生成一个独立集,那么得到的就是最大独立集了。对于Figure 1.1中的示例,它的过程为:

  • 第一步:删除E
  • 第二步:删除D
  • 第三步:最后剩下了“环”,删掉A,F,H

在算法执行的最后,会剩下“环”或是“链”状的图,这时就有可能生成多个最大独立集了。

独立集法求解带权请求策略

在上一篇文章中,我提到了使用独立集的方案,在这里就稍作阐述。问题如下图:


Figure 4.1 An instance of weighted interval scheduling with longest path

首先,我们用请求的权值作为图的点,如果请求a,b冲突,就做边ab,于是得到图:


Figure 4.2 General a graph from the interval

得到了图,下一步就是应用我们的“最大度优先减点法”了,首先删除点E,然后是B,最后得到一个偶数链,删除链中的G以得到最大的权数。最终得到A,C,D,F请求,对应图中的:


Figure 4.3 Result we get from idependent set

实际上,独立集法求解带权请求策略所使用的独立集策略为:最大权重独立集算法,而不是最大独立集算法,所以本处产生的结果不是带权请求的最优结果。关于最大权重独立集算法以后可能会涉及到。

总结

独立集的应用非常广,同时它也非常高效,有时候并不是所有的问题都适合用动态规划等方法,恰当的运用图的理论可以大大提高系统的效率。希望大家检验上面的算法,不吝言辞多提意见。

作者:Creason New(Creason's Blog)
出处: http://www.cnblogs.com/niuchenglei
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

相关阅读 更多 +
排行榜 更多 +
别惹神枪手安卓版

别惹神枪手安卓版

冒险解谜 下载
坦克战争世界

坦克战争世界

模拟经营 下载
丛林反击战

丛林反击战

飞行射击 下载