Maximum clique problem (iterative backtracking method)

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:
Insert picture description here
output:
Insert picture description here

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

Insert picture description here

Reference

Solving the largest clique problem with backtracking method https://blog.csdn.net/practical_sharp/article/details/102791951

More

Guess you like

Origin blog.csdn.net/qq_40649503/article/details/111713309