概述:
最大團問題(Maximum Clique Problem, MCP)是圖論中一個經典的組合優化問題,也是一類NP完全問題。最大團問題又稱為最大獨立集問題(Maximum Independent Set Problem)。目前,求解MCP問題的算法主要分為兩類:確定性算法和啟發式算法。確定性算法有回溯法、分支限界法等,啟發式算法、蟻群算法、順序貪婪算法、DLS-MC算法和智能搜索算法等。
問題描述:
給定無向圖G=(V,E),其中V是頂點集;E是V邊集。如果U屬於V,且對任意兩個頂點u,v∈U有(u,v)∈E,則稱U是G的完全子圖。G的完全子圖U是G的一個團當且僅當U不包含在G的更大的完全子圖中。G的最大團是指G中所含頂點數最多的團。
如果U屬於V,且對任意u,v∈U有(u,v)不屬於E,則稱U是G的空子圖。G的空子圖U是G的獨立集當且僅當U不包含在G的更大的空子圖中。G的最大獨立集是G中所含頂點數最多的獨立集。
對於任一無向圖G=(V,E),其補圖G'=(V',E')定義為:V'=V,且(u,v)∈E'當且僅當(u,v)∉E。
如果U是G的完全子圖,則它也是G'的空子圖,反之亦然。因此,G的團與G'的獨立集之間存在一一對應的關系。特殊地,U是G的最大團當且僅當U是G'的最大獨立集。
算法分析:
無向圖G的最大團和最大獨立集問題都可以用回溯法在O(n2
n)時間內解決。圖G的最大團和最大獨立集問題都可以看作是圖G的頂點集V的子集選取問題。因此可用子集樹表示問題的解空間。
設當前擴展節點
Z
位於解空間
樹的第
i
層。在進入左子樹前,必須確認從頂點
i
到已入選的頂點集中每一個頂點都有邊
相連。在進入右子樹之前,必須確認還有足夠多的可選擇頂點使得算法
有可能在右子樹中找到更大的團。
算法描述:
1 #include <fstream> 2 #include <iostream> 3 #include <stdlib.h> 4 #include <conio.h> 5 using namespace std; 6 7 #define MAX_v 50 //定義一個最大頂點個數 8 typedef struct{ 9 int a[MAX_v][MAX_v]; //無向圖G的鄰接矩陣 10 int v; //無向圖G的頂點 11 int e; //無向圖G的邊 12 int x[50]; //頂點與當前團的連接,x[i]=1 表示有連接——即x[i]==1代表在當前最大團的解內 13 int bestx[50]; //當前最優解 14 int cnum; //當前團的頂點數目 15 int bestn; //最大團的頂點數目 16 }MCP; 17 18 void Creat(MCP &G); 19 void Backtrack(MCP &G,int i); 20 21 void Creat(MCP &G){ 22 int i,j; 23 ifstream fin("data.txt"); 24 if (!fin) 25 { 26 cout<<"不能打開文件:"<<"data.txt"<<endl; 27 exit(1); 28 } 29 fin>>G.v; 30 for (int i=1;i<=G.v;i++) 31 for (int j=1;j<=G.v;j++) 32 fin>>G.a[i][j]; 33 for(i=1;i<=G.v;i++) //初始化 34 { 35 G.bestx[i]=0; 36 G.x[i]=0; 37 G.bestn=0; 38 G.cnum=0; 39 } 40 cout<<"———回溯法求解最大團問題———"<<endl; 41 cout<<"輸入初始化無向圖矩陣為:"<<endl; //初始化 42 for(i=1;i<=G.v;i++) 43 { 44 for(j=1;j<=G.v;j++) 45 cout<<G.a[i][j]<<" "; 46 cout<<endl; 47 } 48 } 49 50 void Backtrack(MCP &G,int i){ 51 if (i>G.v){ //output()階段 52 for (int j=1; j<=G.v; j++) 53 G.bestx[j] = G.x[j]; //記錄最優解 54 G.bestn =G.cnum; 55 return ; 56 } 57 //檢查頂點i與當前團的連接 58 int OK = 1; 59 for (int j=1; j<=i ; j++) 60 if (G.x[j]&& G.a[i][j]==0){ //G.x[j]:頂點j在當前解的最大團內;G.a[i][j]:待考察i頂點與最大團中前i-1個頂點間邊的關系 61 //i不與j相連 62 OK = 0; 63 break; 64 } 65 if (OK) { //進入左子樹 66 G.x[i] = 1;//把i加入團 67 G.cnum++; 68 Backtrack(G,i+1); 69 G.x[i]=0; 70 G.cnum-- ; 71 } 72 if (G.cnum+G.v- i>G.bestn){ //進入右子樹——剪枝函數 73 G.x[i] = 0; 74 Backtrack(G,i+1); 75 } 76 } 77 78 int main(){ 79 MCP G; 80 Creat(G); 81 Backtrack(G,1); 82 cout<<"最大團包含的頂點數為:"<<G.bestn<<endl; 83 cout<<"最大團方案為:( "; 84 for (int i=1;i<=G.v;i++) 85 if(G.bestx[i]==1){ 86 cout<<i<<" "; 87 } 88 cout<<")"<<endl; 89 getch(); 90 }
注:問題在於這種解法只能求得其中的一個最大團解!
最大團問題百度百科:http://baike.baidu.com/view/7343867.htm
