问题描述:
给定一个无向图G=(V,E)。若UÍV,且对任意的u,vÎU, 都有边(u,v)ÎE, 则称U是图G的一个完全子图。 G的完全子图U是一个团,当且仅当U不包含在G的更大的完全子图中。G的最大团是指包含顶点数最多的团。
最大团问题是,对给定的无向图,找出最大团中顶点的个数。
算法思路:
首先最大团是一个空团(即不包含任何一个顶点的团),然后把每一个顶点依次加入团中。加入当前顶点i时,需要考虑当前顶点i是否与所有已经加入团的顶点邻接。如果不邻接,直接跳过该顶点,考虑下一个顶点。如果邻接,还需要考虑两种情况:一种是把当前顶点i加入团中,然后递归考虑后面的顶点;另一种是不把当前顶点i放入团中,然后递归考虑后面的顶点。直到所有的顶点都考虑完后,判断当前的最有解是否比之前的最优解更优。如果更优,用当前最优解替代之前的最优解,回溯;如果不是更优,回溯。直到将整个子集树遍历完,算法结束。
约束函数:当前顶点i要与选入顶点集的每一个顶点邻接
上界函数:有足够多的可选顶点使有可能在右子树找到最大团
代码附录:
int n, //图顶点数
cn = 0, // 当前的顶点集的顶点数
bestn = 0; // 之前最优解集的顶点数
int **m, // 图的邻接矩阵
*x, // 记录顶点是否放入顶点集
*bestx; // 记录最优解集的顶点
void BackTrack(int t){
if(t>n){
for(int i=1; i<=n; i++) bestx[i] = x[i];
bestn = cn;
return;
}
int ok = 1;
// 约束函数
for(int j=1; j<t; j++){
if(x[j] && m[j][t] == 0 ){
ok = 0;
break;
}
}
// 当前顶点t与顶点集的顶点邻接,并将顶点t放入顶点集
if(ok){
x[t] = 1;
cn++;
BackTrack(t+1);
cn--;
x[t] = 0;
}
// 上界函数
if(cn+n-t > bestn){
x[t] = 0;
BackTrack(t+1);
}
}