Maximum clique problem (iterative backtracking method)
problem
Design an iterative backtracking method for solving the largest clique problem
understanding
Given an undirected connected graph G = (V,E), where V is a non-empty set, called a vertex set; E is a set of unordered two-tuples composed of elements in V, called an edge set, in the undirected graph The edges are all unordered pairs of vertices. Unordered pairs are usually represented by parentheses "()". If UϵV, and for any two vertices u, vϵU has (u,v) ϵE, then U is said to be a complete subgraph of G , The holograph of G is the clique of G only if U is not included in the larger holograph of G. The largest clique of G refers to the clique with the largest number of vertices in G.
Ideas
First, set the largest group as an empty group, add a vertex to it, and then consider each vertex in turn, and check that the vertex still forms a group after adding it to the group. If possible, consider adding the vertex to the group or discarding it. If not, , Directly discard, and then recursively judge the next vertex. For the two cases of no connection or direct abandonment, before recursion, the pruning strategy can be used to avoid invalid search.
In order to judge whether the current vertex is still a clique after joining the clique, it is only necessary to consider whether the vertex and the vertices in the clique are connected.
A relatively simple pruning strategy is adopted in the program, that is, if the number of remaining unconsidered vertices plus the number of vertices in the clique is not greater than the number of vertices in the current solution, the deep search can be stopped, otherwise the deep recursion can continue.
C code implementation
#include <iostream>
using namespace std;
class Clique
{
friend void MaxClique( int **, int *, int );
private :
void Backtrack( int i);
int **a; //图的邻接矩阵
int n; //图 的顶 点数
int *x; //当前解
int *bestx; //当前最优解
int cn; //当前顶点数
int bestn; //当前 最 大顶点数
};
void Clique::Backtrack( int i)
{
//计算最大团
if (i>n) //到达叶子节点
{
for ( int j=1;j<=n;j++)
bestx[j]=x[j];
bestn=cn;
cout<< "最大团:(" ;
for ( int i=1;i<n;i++)
cout<<bestx[i]<< "," ;
cout<<bestx[n]<< ")" <<endl;
return ;
}
//检 查 当前顶点是否与当前团连接
int ok=1;
for ( int j=1;j<i;j++)
if (x[j]&&a[i][j]==0) //i与j不连接,即j在团中,但是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);
}
}
void MaxClique( int **a, int *v, int n)
{
//初始化 Y
Clique Y;
Y.x= new int [n+1];
Y.a=a;
Y.n=n;
Y.cn=0;
Y.bestn=0;
Y.bestx=v;
Y.Backtrack(1);
delete [] Y.x;
cout<< "最大团的顶点数:" <<Y.bestn<<endl;
}
int main()
{
int n;
cout<< "please input number of node:" ;
cin>>n;
//int a[n+1][n+1]; //由于定义的是int **a,且采用的是二维数组传参,因此
int **a= new int *[n+1]; //两种解决方法,一是给定第二维的大小,二是通过
for ( int k=0;k<=n;k++) //动态分配内存,这里采用了动态内存分配解决问题
a[k]= new int [n+1];
for ( int i=0;i<n+1;i++)
for ( int j=0;j<n+1;j++)
a[i][j]=0;
int edge;
cout<< "please input number of edge:" ;
cin>>edge;
cout<< "please input edge:" <<endl;
int v,w;
for ( int x=0;x<edge;x++)
{
cin>>v>>w;
a[v][w]=1;
a[w][v]=1;
}
int *p= new int [n+1];
MaxClique(a,p,n);
system( "pause" );
return 0;
}
test
When the input diagram:
output:
Reference
Backtracking experiment (the biggest group problem) https://wenku.baidu.com/view/fdb2875fe418964bcf84b9d528ea81c758f52e32.html
C code implementation 2
#include <iostream>
using namespace std;
int m[101][101];//有向图的邻接矩阵
int x[101];//当前团的解
int bestx[101];//最优解
int n;//表示图的顶点数
int cn=0;//当前团的大小
int bestn;//当前最优值
void getbestn(int i)
{
if(i>n){
//递归出口,到根节点时,更新最优值和最优解,返回
bestn=cn;//更新最优值
for(int j=1;j<=n;j++)
bestx[j]=x[j];
return ;//返回
}
x[i]=1;//先假定x[i]=0;
for(int j=1;j<i;j++){
if(x[j]==1&&m[i][j]==0){
x[i]=0;//如果该点与已知解中的点无边相邻
break;//则不遍历左子树
}
}
if(x[i]==1){
//当且仅当x[i]==1时,遍历左子树
cn++;//该点加入当前解
getbestn(i+1);//递归调用
cn--;//还原当前解
}
x[i]=0;//假定x[i]==0
if(cn+n-i>bestn){
//如果当前值+右子树可能选择的节点<当前最优解,不遍历左子树
x[i]=0;
getbestn(i+1);
}
return ;
}
int main()
{
printf("输入图的顶点数:\n");
scanf("%d",&n);
//输入图的顶点数
//输入图的邻接矩阵
printf("输入图的邻接矩阵:\n");
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&m[i][j]);
//求最优解
getbestn(1);
//输出最优值
printf("最优值:%d\n",bestn);
//输出
for(int k=1;k<=n;k++)
if(bestx[k])
//输出最优解
printf("最优解:%-2d",k);
printf("\n");
return 0;
}
test
Reference
Solving the largest clique problem with backtracking method https://blog.csdn.net/practical_sharp/article/details/102791951
More
- Backtracking method-the largest group problem https://www.jianshu.com/p/99ed0f46b94c
- Algorithm implementation in java-backtracking method-the largest group problem
https://blog.csdn.net/lican19911221/article/details/26228345 - Algorithm design and analysis-the largest group problem (backtracking method) https://www.cnblogs.com/wkfvawl/p/11923848.html
- Chapter 5 [Backtracking] The problem of the largest group and the m coloring problem of the graph https://blog.csdn.net/weinierbian/article/details/50379376