最大团问题回溯法求解

问题描述

完全子图:给定无向图G=(V,E)。如果U<=V,且对任意u,v<=U有(u,v)<=E,则称U是G的完全子图。
:G的完全子图U是G的团当且仅当U不包含在G的更大的完全子图中。
G的最大团:是指G中所含顶点数最多的团。

在这里插入图片描述

{1,2}是G的完全子图,但不是团,因为它被更大的完全子图
{1,2,5}包含。{1,2,5}、{1,4,5}和{2,3,5}都是最大团。

思路

解空间:子集树
可行性约束函数:顶点i到已选入的顶点集中每一个顶点都有边相连。
限界函数:有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。
复杂度分析:最大团问题的回溯算法backtrack所需的
计算时间显然为O(n2n)。

输入

第一行输入一个数n,表示图的顶点数
第二行到第n+1行表示图的邻接矩阵

5
0 1 0 1 1
1 0 1 0 1
0 1 0 0 1
1 0 0 0 1
1 1 1 1 0

输出

输出有两行
第一行表示最优值,最大团的顶点数
第二行表示最优解,最大团中的顶点编号,每一个编号中间有一个空格

3
1 2 5

代码

#include <iostream>
using namespace std;
int m[101][101];//有向图的邻接矩阵
int x[101];//当前团的解
int bestx[101];//最优解
int n;//表示图的顶点数
int cn=0;//当前团的大小
int bestn;//当前最优值
void getbestn(int i)
{
    if(i>n){//递归出口,到根节点时,更新最优值和最优解,返回
        bestn=cn;//更新最优值
        for(int j=1;j<=n;j++)
            bestx[j]=x[j];
        return ;//返回
    }
    x[i]=1;//先假定x[i]=0;
    for(int j=1;j<i;j++){
        if(x[j]==1&&m[i][j]==0){
            x[i]=0;//如果该点与已知解中的点无边相邻
            break;//则不遍历左子树
        }
    }
    if(x[i]==1){//当且仅当x[i]==1时,遍历左子树
        cn++;//该点加入当前解
        getbestn(i+1);//递归调用
        cn--;//还原当前解
    }
    x[i]=0;//假定x[i]==0
    if(cn+n-i>bestn){//如果当前值+右子树可能选择的节点<当前最优解,不遍历左子树
        x[i]=0;
        getbestn(i+1);
    }
    return ;
}
int main()
{
    cin>>n;//输入图的顶点数
    //输入图的邻接矩阵
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        cin>>m[i][j];
    //求最优解
    getbestn(1);
    cout<<bestn<<endl;//输出最优值
    //输出
    for(int i=1;i<=n;i++)
        if(bestx[i])
        cout<<i<<" ";//输出最优解
    return 0;
}

在这里插入图片描述

发布了97 篇原创文章 · 获赞 101 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/practical_sharp/article/details/102791951