回溯法——最大團問題(Maximum Clique Problem, MCP)


概述:

  最大團問題(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 位於解空間 樹的第  層。在進入左子樹前,必須確認從頂點  到已入選的頂點集中每一個頂點都有邊 相連。在進入右子樹之前,必須確認還有足夠多的可選擇頂點使得算法 有可能在右子樹中找到更大的團。

算法描述:

 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 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM