当前位置:   article > 正文

回溯算法 --- 例题6.最大团问题_给定无向图g的节点集合及邻接矩阵,求解该无向图的最大团。c++

给定无向图g的节点集合及邻接矩阵,求解该无向图的最大团。c++
一.问题描述

给定无向图G=(V, E), U⊆V, 若对任意u, v∈U, 有(u,v) ∈ E, 则称U是G的一个完全子图.
G的完全子图U是G的一个团当且仅当U不包含在G的更大的完全子图中,G的最大团是指G中所含顶点数最多的团.

二.解题思路

无向图G的最大团和最大独立集问题都可以用回溯法在O(n2^n)时间内解决.图G的最大团和最大独立集问题都可以看做图G的顶点集V的子集选取问题.因此,我们可以用子集树表示问题的解空间.

解最大团问题的回溯法和解装载问题的回溯法十分相似.设当前扩展结点Z位于解空间树的第i层.在进入左子树前,必须确认还有足够多的可选择顶点,使得算法有可能在右子树中找到更大的集.

具体代码如下:

// 最大团问题
#include<bits/stdc++.h>
using namespace std;
class Clique
{
    friend int MaxClique(int **, int *, int);
    private:
        void Backtrack(int i);
        int **a,        //图G的邻接矩阵
            n,          //图G的顶点数
            *x,         //当前解
            *bestx,     //当前最优解
            cn,         //当前顶点数
            bestn;      //当前最大顶点数
};
void Clique::Backtrack(int i)   //计算最大团
{
    static int k = 1;
    if(i > n)
    {
        cout<<"第"<<k++<<"次到达叶节点,此时的到最大团顶点数为:"<<cn<<endl;
        cout<<"顶点选择情况为:";
        for(int j=1; j<=n; j++)
        {
            bestx[j] = x[j];
            cout<<x[j]<<" ";
        }
        cout<<endl;
        bestn = cn;
        return ;
    }
    //检查顶点i与当前团的连接
    bool CanSelect = true;
    for(int j=1; j<i; j++)
    {
        if(x[j] && a[i][j] == 0) //i与j不相连
        {
            CanSelect = false;
            break;
        }
    }
    if(CanSelect)  //进入左子树
    {
        x[i] = 1;
        cn++;
        cout<<"进入左子树深入一层,将到达第"<<i+1<<"层"<<endl;
        Backtrack(i+1);
        cout<<"从左子树回溯一层,将到达第"<<i<<"层"<<endl;
        x[i] = 0;
        cn--;
    }
    else cout<<"顶点i不与当前团处于连接状态,所以尝试往右"<<endl;
    if(cn+n-i >= bestn)  //如果右子树中剩余所有结点个数加起来大于等于当前最大顶点数,那么进入右子树.
    {
        cout<<"进入右子树深入一层,将到达第"<<i+1<<"层"<<endl;
        x[i] = 0;  //该句可要可不要
        Backtrack(i+1);
        cout<<"从右子树回溯一层,将到达第"<<i<<"层"<<endl;
    }
    else cout<<"右子树中剩余所有顶点数加上当前已经选择的顶点数一共为:"<<cn+n-i<<"  小于当前最大顶点数:"<<bestn<<",直接剪枝.";
}
int MaxClique(int **a, int *v, int n)
{
    Clique Y;
    //初始化Y
    Y.x = new int[n+1];
    Y.a = a;
    Y.n = n;
    Y.cn = 0;
    Y.bestn = 0;
    Y.bestx = new int[n+1];
    Y.Backtrack(1);
    delete[] Y.x;
    return Y.bestn;
}
int main()
{
    cout<<"请输入顶点个数:";
    int n;
    while(cin>>n && n)
    {
        cout<<"请输入邻接矩阵"<<endl;
        int **a = new int*[n+1];
        for(int i=0; i<=n; i++) a[i] = new int[n+1];
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=n; ++j)
                cin>>a[i][j];
        int *v = new int[n+1];
        for(int i=0; i<=n; i++) v[i] = 0;
        int ans = MaxClique(a, v, n);
        cout<<"最大团中顶点个数为:"<<ans<<endl;
        for(int i=0; i<=n; i++) delete[] a[i];
        delete[] a;
        cout<<"请输入顶点个数:";
    }
    system("pause");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

运行结果如下:

由此构建出的的子集树为:

应该比较清晰,大家可以试着自己画一画.

参考毕方明老师《算法设计与分析》课件.

欢迎大家访问个人博客网站—乔治的编程小屋,一起加油!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/807023?site
推荐阅读
相关标签
  

闽ICP备14008679号