最大團問題回溯法求解

問題描述

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

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章