算法設計與分析——最大團問題(回溯法)


一、問題描述

了解最大團問題(Maximum Clique Problem, MCP)之前需要明白幾個概念。復習一下圖論知識......

完全圖:如果無向圖中的任何一對頂點之間都有一條邊,這種無向圖稱為完全圖。

完全子圖:給定無向圖G=(V,E)。如果UV,且對任意u,vU 有(u,v)  E,則稱U 是G 的完全子圖。

團(最大完全子圖): U是G的團當且僅當U不包含在G 的更大的完全子圖中

最大團:G 的最大團是指G中所含頂點數最多的團。

空子圖:給定無向圖G=(V,E)。如果UV,且對任意u,vU 有(u,v) ∉ E,則稱U 是G 的空子圖。G的空子圖U是G的獨立集當且僅當U不包含在G的更大空子圖中。

獨立集:對於給定無向圖G=(V,E)。如果頂點集合V*V,若V*中任何兩個頂點均不相鄰,則稱V*為G的點獨立集,或簡稱獨立集。

最大獨立集:G中所含頂點數最多的獨立集。

例如:

                               

                 (a)                                        (b)                             (c)                            (d)

圖a是一個無向圖,圖b、c、d都是圖a的團,且都是最大團。

補圖:

圖G的補圖,通俗的來講就是完全圖Kn去除G的邊集后得到的圖Kn-G。在圖論里面,一個圖G的補圖(complement)或者反面(inverse)是一個圖有着跟G相同的點,而且這些點之間有邊相連當且僅當在G里面他們沒有邊相連。

 

 

二、算法設計

 

 大致思路:

首先設最大團為一個空團,往其中加入一個頂點,然后依次考慮每個頂點,查看該頂點加入團之后仍然構成一個團,如果可以,考慮將該頂點加入團或者舍棄兩種情況,如果不行,直接舍棄,然后遞歸判斷下一頂點。對於無連接或者直接舍棄兩種情況,在遞歸前,可采用剪枝策略來避免無效搜索。

為了判斷當前頂點加入團之后是否仍是一個團,只需要考慮該頂點和團中頂點是否都有連接。

程序中采用了一個比較簡單的剪枝策略,即如果剩余未考慮的頂點數加上團中頂點數不大於當前解的頂點數,可停止繼續深度搜索,否則繼續深度遞歸。

三、實例分析

如圖1所示,給定無向圖G={V, E},其中V ={1,2,3,4,5},E={(1,2), (1,4), (1,5), (2,3), (2,5), (3,5), (4,5)}。根據MCP定義,子集{1,2}是圖G的一個大小為2的完全子圖,但不是一個團,因為它包含於G的更大的完全子圖{1,2,5}之中。{1,2,5}是G的一個最大團。{1,4,5}和{2,3,5}也是G的最大團。

圖2是無向圖G的補圖G'。根據最大獨立集定義,{2,4}是G的一個空子圖,同時也是G的一個最大獨立集。雖然{1,2}也是G'的空子圖,但它不是G'的獨立集,因為它包含在G'的空子圖{1,2,5}中。{1,2,5}是G'的最大獨立集。{1,4,5}和{2,3,5}也是G'的最大獨立集。

 

以圖1為例,利用回溯法搜索其空間樹,具體搜索過程(見圖3所示)如下:假設我們按照1®2®3®4®5的順序深度搜索。

開始時,根結點R是唯一活結點,也是當前擴展結點,位於第1層,此時當前團的頂點數cn=0,最大團的頂點數bestn=0。

在這個擴展結點處,我們假定R和第二層的頂點1之間有邊相連,則沿縱深方向移至頂點1處。此時結點R和頂點1都是活結點,頂點1成為當前的擴展結點。此時當前團的頂點數cn=1,最大團的頂點數bestn=0。繼續深度搜索至第3層頂點2處,此時頂點1和2有邊相連,都是活結點,頂點2成為當前擴展結點。

此時當前團的頂點數cn=2,最大團的頂點數bestn=0。再深度搜索至第4層頂點3處,由於頂點3和2有邊相連但與頂點1無邊相連,則利用剪枝函數剪去該枝,此時由於cn+n-i=2+5-4=3>bestn=0,則回溯到結點2處進入右子樹,開始搜索。此時當前團的頂點數cn=2,最大團的頂點數bestn=0。再深度搜索至第5層頂點4處,由於頂點3和4無邊相連,剪去該枝,回溯到結點3處進入右子樹,此時當前團的頂點數cn=2,最大團的頂點數bestn=0。

繼續深度搜索至第6層頂點5處,由於頂點5和4有邊相連,且與頂點1和2都有邊相連,則進入左子樹搜索。由於結點5是一個葉結點,故我們得到一個可行解,此時當前團的頂點數cn=3,最大團的頂點數bestn=3。vi的取值由頂點1至頂點5所唯一確定,即v=(1, 2, 5)。此時頂點5已不能再縱深擴展,成為死結點,我們返回到結點4處。由於此時cn+n-i=3+5-6=2<bestn=3,不能在右子樹中找到更大的團,利用剪枝函數可將結點4的右結點剪去。以此回溯,直至根結點R再次成為當前的擴展結點,沿着右子樹的縱深方向移動,直至遍歷整個解空間。最后得到圖1的按照1®2®3®4®5的順序深度搜索的最大團為U={1,2,5}。當然{1,4,5}和{2,3,5}也是其最大團。

 四、代碼描述

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxnum=101;
bool a[maxnum][maxnum];//圖的鄰接矩陣
bool x[maxnum]; //當前解
int cn;//當前團的頂點數
int bestn;//當前的最優解
int n;//圖G的頂點數
int e;//圖G的邊數
void backtrack(int i)
{
    int j;
    if(i>n)
    {
        bestn=cn;
        printf("%d\n",bestn);
        for(j=1; j<=n; j++)
        {
            if(x[j])
            {
                printf("%d ",j);
            }
        }
        printf("\n");
        return ;
    }

    bool ok=true;
    for(j=1; j<i; j++)
    {
        if(x[j]&&!a[j][i])//i與j不相連
        {
            ok=false;
            break;
        }
    }
    if(ok)//進入左子樹
    {
        cn++;
        x[i]=true;
        backtrack(i+1);
        cn--;
    }
    if(cn+n-i>bestn)  //剪枝
    {
        x[i]=false;
        backtrack(i+1);
    }
}

int main()
{
    int i,u,v;
    memset(a,false,sizeof(a));
    memset(x,false,sizeof(x));
    scanf("%d%d",&n,&e);
    for(i=0; i<e; i++)
    {
        scanf("%d%d",&u,&v);
        a[u][v]=true;
        a[v][u]=true;
    }
    cn=bestn=0;
    backtrack(1);
    return 0;
}

/*
5 7
1 2
1 4
1 5
2 5
2 3
3 5
4 5
*/

 


免責聲明!

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



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