算法复习:最大团问题(回溯法和分支限界法)

问题描述
给定无向图G=(V,E),V是顶点集,E是边集。如果U V,且对任意u,v U有(u,v) E,u,v是两个顶点的符号,则称U是G的完全子图。G的完全子图U是G的一个团当且仅当U不包含在G的更大的完全子图中。

2、一个例子
《算法复习:最大团问题(回溯法和分支限界法)》
–子集{1,2}是G的一个大小为2的完全子图,但不是一个团,因为它包含于G的更大的完全子图{1,2,5}中。{1,2,5}、{1,4,5}和{2,3,5}都是G的最大团。

A 回溯法:

·问题空间(input):
-G=(V,E)
·解空间(output):
-图G的顶点集V的子集选取问题,Xi {0,1}
-约束函数:团的定义
-目标函数:所含顶点数最多
·解空间树(所有可能解的结构):
-子集数(因为这是一个子集选取问题)
·搜索空间(最优解的求解过程):
-约束函数 顶点i到已选入的顶点集中每一个顶点都有边相连。
-限界函数 有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。

下面是根据图构造出来的树(没有构造完,虚线的地方可以继续往下画,相应的下面的表也是):
《算法复习:最大团问题(回溯法和分支限界法)》
cn是当前顶点数,bestn是当前最大顶点数
下面的表是搜索过程:
《算法复习:最大团问题(回溯法和分支限界法)》
Xi分别代表五个点,值为0代表没有选入顶点集U,值为1代表已选入顶点集U。
3、算法部分代码


int **a         //图G的邻接矩阵
int n           //图G的顶点数
int *x          //当前解
int *bestx      //当前最优解
int cn          //当前顶点数
int bestn       //当前最大顶点数


void MaxClique(int i)
{
    if (i > n)      //到达叶节点,更新最优值和最优解
    {
        for (int j = 1;j <= n;j++)
            bestx[j] = x[j];
        bestn = cn;
        return;
        //搜索扩展节点时,检查顶点i与当前团的连接
    }
    int OK = 1;
    for (int j = 1;j < i;j++)//扫描当前团
        if (x[j] && a[i][j] == 0)//i与当前团的顶点j不相连
        {
            OK = 0;
            break;
        }
    if (OK)//顶点i与当前团的每个顶点均有连接,进入左子树
    {
        x[i] = 1;//状态更新
        cn++;
        MaxClique (i + 1);
        x[i] = 0;//输出叶节点后,搜索右子树之前的状态恢复(即回溯指搜索右子树)
        cn--;
    }
    if (cn + n - i > bestn)//进入右子树
    {
        x[i] = 0;
        MaxClique(i + 1);
    }
}

4、算法效率
解最大团问题的回溯算法所需的计算时间为O(n 2n )

B 分支限界法
优先队列式分支限界法
还是上面那题,图片再复制到这里
《算法复习:最大团问题(回溯法和分支限界法)》
·解空间和解空间树都没变
·剪枝
-左子树:从顶点i到已选入的顶点集中每一个顶点都有边,否则剪枝
-右子树:顶点数上界小于当前最优值(就是上面的bestn)时剪枝
顶点数上界=已确定的顶点数+未确定的顶点数的上界
·优先队列中节点的优先级
-顶点数上界

解空间树如下:
《算法复习:最大团问题(回溯法和分支限界法)》
现在懂节点上那两数字相加啥意思了吧

树搜索的过程如下表:
《算法复习:最大团问题(回溯法和分支限界法)》

所以,这已经很明白了,回溯法求解搜索树是深度优先,先一条道走到底,再回溯找其他的看是不是比得到的最优,而分支限界是广度优先,一层一层往下找,中间不断排除不符合的,找到最下面一层就得到了最优解。

    原文作者:分支限界法
    原文地址: https://blog.csdn.net/qq_18995813/article/details/51547099
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞