問題描述
完全子圖:給定無向圖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;
}