问题描述
完全子图:给定无向图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;
}