采用回溯法。 1表示选取某个顶点,0表示不选取,从而形成了一个n维的解空间,把解空间组织成树,然后深度优先搜索这棵树。深度为t的结点表示是否选取编号为t+1的顶点。当遍历到叶子结点时,说明找到了目前为止的最大的团的顶点数。当还没遍历到叶子结点时,如果满足顶点t+1和已选取的所有顶点都有边,则选取该顶点,并深度优先遍历左子树。否则,如果不选取该顶点也有希望获得比得到比原来最大顶点数还要大的顶点数的话,则深度优先搜索右子树。
#include <iostream>
using namespace std;
int max_vertex = 0; //记录目前得到的最大团的顶点数
int cn = 0, fn = 0;
bool choose[100] = { 0 }; //表示是否选取某个顶点,1表示选取,0表示不选取
bool place(int t, int** graph) //判断t是否和已选取的顶点都有边
{
for (int i = 0; i < t; i++)
{
if (choose[i] && graph[i][t] == 0) //如果顶点i已被选取,并且和顶点t没有边
return false;
}
return true;
}
void traceback(int t, int n, int** graph) //深度优先搜索以顶点t为根的子树
{
if (t == n) //当遍历到叶子顶点时
{
max_vertex = cn; //把当前已选取的顶点数作为目前的最大顶点数
}
else
{
if (place(t, graph)) //如果顶点t和已选取的顶点都有边
{
choose[t] = 1;
cn++;
traceback(t + 1, n, graph); //遍历左子树
choose[t] = 0;
cn--;
}
fn = n - t;
if (cn + fn > max_vertex) //如果遍历右子树也有希望得到比原来最大顶点数还要大的顶点数的话
{
choose[t] = 0;
traceback(t + 1, n, graph); //遍历右子树
}
}
}
int maximum_clique(int n, int** graph) //得到最大团顶点数
{
traceback(0, n, graph);
return max_vertex;
}
int main(void)
{
int n, m, vertex1, vertex2, max_vertex_list[100], k = 0;
cin >> n >> m;
while (n != 0 && m != 0)
{
int** graph = new int* [n]; //建立n行n列的二维数组graph[][],作为图的邻接矩阵
for (int i = 0; i < n; i++)
graph[i] = new int[n];
for (int i = 0; i < n; i++) //初始化数组graph[][]
{
for (int j = 0; j < n; j++)
graph[i][j] = 0;
}
for (int i = 0; i < m; i++) //输入边
{
cin >> vertex1 >> vertex2;
graph[vertex1 - 1][vertex2 - 1] = 1;
graph[vertex2 - 1][vertex1 - 1] = 1;
}
max_vertex_list[k] = maximum_clique(n, graph);
k++;
for (int i = 0; i < n; i++) //释放graph
{
delete[] graph[i];
}
delete[] graph;
cin >> n >> m;
}
for (int i = 0; i < k; i++) //输出结果
cout << max_vertex_list[i] << endl;
return 0;
}
运行结果: