完全子图:子图U属于图G,且子图U中各顶点v两两相连;
团:如果完全子图U不被其他子图包含,则该完全子图U为团C;
最大团:图G中顶点数目最多的团C
算法步骤:
(1)将图G表示为矩阵M,矩阵元素值描述为行号对应节点与列号对应节点的连接状态,连接则为1,不连接则为0;
(2)以最小下标对应节点作为起始节点,如以下标为0的节点作为起始节点。
(3)将0号节点放入团中,当前顶点数cn为1,接着输入1号节点,M[1][0]=1,则将1号节点放入团中,cn=2。
(4)输入2号节点,M[2[0]=1,M[2][1]=0,则2号节点与现有团无法构成团;输入3号节点同样无法与现有团构成团。
(5)输入5号节点,M[5[0]=1,M[5][1]=1,则将5号节点放入团中,cn=3。
(6)第一次迭代结束,bestcn=cn=3,cn=1。从剩余节点中导入新的节点,若cn+N-i<bestcn,则跳出循环;否则,继续处理步骤(2)(3)(4)(5)(6)。
若得到多个团,取节点数最多的团作为最大团。该实验最终输出结果为:{1,2,5}。
代码:
//最大团问题 回溯法求解
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;
const int N = 5;//图G的顶点数
ifstream fin("5d7.txt");
class Clique
{
friend int MaxClique(int **, int[], int);
private:
void Backtrack(int i);
int **a, //图G的邻接矩阵
n, //图G的顶点数
*x, //当前解
*bestx, //当前最优解
cn, //当前顶点数
bestn; //当前最大顶点数
};
int MaxClique(int **a, int v[], int n);
int main()
{
int v[N + 1];
int **a = new int *[N + 1];
for (int i = 1; i <= N; i++)
{
a[i] = new int[N + 1];
}
cout << "图G的邻接矩阵为:" << endl;
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
fin >> a[i][j];
cout << a[i][j] << " ";
}
cout << endl;
}
cout << "图G的最大团解向量为:" << endl;
cout << "图G的最大团顶点个数为:" << MaxClique(a, v, N) << endl;
for (int i = 1; i <= N; i++)
{
delete[] a[i];
}
delete[]a;
return 0;
}
// 计算最大团
void Clique::Backtrack(int i)
{
for (int i = 1; i <= N; i++)
std::cout << x[i] << " ";
std::cout << endl;
if (i > n) // 到达叶结点
{
for (int j = 1; j <= n; j++)
{
bestx[j] = x[j];
cout << x[j] << " ";
}
cout << endl;
bestn = cn;
return;
}
// 检查顶点 i 与当前团的连接
int OK = 1;
for (int j = 1; j < i; j++)
{
cout << "x[" << j << "]=" << x[j] << endl;
cout <<"a["<<i<<","<<j<<"]="<<a[i][j] << endl;
if (x[j] && a[i][j] == 0)
{
// i与j不相连
OK = 0;
break;
}
}
if (OK)// 进入左子树
{
x[i] = 1;
cn++;
Backtrack(i + 1);
x[i] = 0;
cn--;
}
if (cn + n - i >= bestn)// 进入右子树
{
x[i] = 0;
Backtrack(i + 1);
}
}
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 = v;
for (int i = 1; i <= N; i++)
std::cout << Y.x[i] << " ";
std::cout << endl;
Y.Backtrack(1);
delete[] Y.x;
return Y.bestn;
}