回溯法——最大团问题

回溯法——最大团问题

问题:

给定无向图G=(V,E)。如果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=(V1,E1)定义为:V1=V,且(u,v)∈E1当且仅当(u,v)∉E。

求原图的最大独立集等价于求补图的最大团。无向图G的最大团和最大独立集问题可以看作是图G的顶点集V的子集选取问题。如同装载问题。

分析:

与装载问题是类似的,都是1-0子集树。约束函数:每个选了的顶点之间两两相连。限制函数:已经选了的点加上剩下的点大于当前的最优解。

代码:

#include <bits/stdc++.h>

using namespace std;

#define MAXN 105

// 用邻接矩阵来存储图
int m[MAXN][MAXN];

// 最优解
int bestGroup = -1;

// 结果记录数组
int res[MAXN];

// 最终结果数组
int bestRes[MAXN];

// 约束函数
bool constrain(int pos){
    for(int i = 1;i <= pos;i++){
        if(res[i]){
            for(int j = 1;j <= pos;j++){
                if(j == i) continue;
                if(res[j] && !m[i][j]){
                    return false;
                }
            }
        }
    }
    return true;
}

// 计算当前解
int sum(int pos){
    int tmp = 0;
    for(int i = 1;i <= pos;i++){
        if(res[i]) tmp++;
    }
    return tmp;
}

// 限界函数
bool bound(int pos,int n){
    return sum(pos) + n - pos > bestGroup;
}

// 递归求解最大团问题
void maxGroupTraceback(int pos,int n){
    // 找到了一个最优解
    if(pos > n){
        bestGroup = sum(n);
        for(int i = 0;i <= n;i++)
            bestRes[i] = res[i];
    }else{
        // 左子树
        res[pos] = 1;
        if(constrain(pos)){
            maxGroupTraceback(pos+1, n);
            res[pos] = 0;
        }
        
        res[pos] = 0;
        if(bound(pos,n)){
            maxGroupTraceback(pos+1, n);
        }
    }
}

int main(){
    int n = 5;
    
    memset(m, 0, sizeof(m));
    memset(res, 0, sizeof(res));
    memset(bestRes, 0, sizeof(bestRes));
    
    m[1][2] = 1;
    m[1][4] = 1;
    m[1][5] = 1;
    m[2][3] = 1;
    m[2][5] = 1;
    m[3][5] = 1;
    m[4][5] = 1;

    m[2][1] = 1;
    m[4][1] = 1;
    m[5][1] = 1;
    m[3][2] = 1;
    m[5][2] = 1;
    m[5][3] = 1;
    m[5][4] = 1;
    
    maxGroupTraceback(1, n);
    
    for(int i = 1;i <= n;i++){
        if(bestRes[i]) cout<<i<<" ";
    }
    
    cout<<endl<<bestGroup<<endl;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值