回溯法-最大团问题

一、 问题描述

  给定无向图G=(V,E)。如果UV,且对任意u,v∈U 有(u,v)∈E,则称U 是G 的完全子图。G 的完全子图U是G的团当且仅当U不包含在G 的更大的完全子图中,即U就是最大完全子图。G 的最大团是指G中所含顶点数最多的团。

  如果U属于V,且对任意u,v∈U有(u,v)不属于E,则称U是G的空子图。G的空子图U是G的独立集当且仅当U不包含在G的更大的空子图中。G的最大独立集是G中所含顶点数最多的独立集。对于任一无向图G=(V,E),其补图G'=(V',E')定义为:V'=V,且(u,v)∈E'当且仅当(u,v)∉E。如果U是G的完全子图,则它也是G'的空子图,反之亦然。因此,G的团与G'的独立集之间存在一一对应的关系。特殊地,U是G的最大团当且仅当U是G'的最大独立集。

二、 解题思路及所选算法策略的可行性分析

  无向图G的最大团和最大独立集问题都可以用回溯法在O(n2n)时间内解决。图G的最大团和最大独立集问题都可以看作是图G的顶点集V的子集选取问题。因此可用子集树表示问题的解空间。设当前扩展节点Z位于解空间树的第i层。在进入左子树前,必须确认从顶点i到已入选的顶点集中每一个顶点都有边相连。在进入右子树之前,必须确认还有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。

三、 伪代码描述及复杂度分析

时间复杂度:O(n2n)

空间复杂度:O(n2)

四、 代码实现

(代码是别人的)代码实现:

package com.handsometaoa;

public class Maxclique {

public int[] x; //当前解(x[i]=1表示i点在最大团中,=0表示不在团中)

public int n; //图G的顶点数

public int cn; //当前顶点数

public int bestn; //当前最大顶点数

public int[] bestx; //当前最优解

public int[][] a; //图G的邻接矩阵,0:不连通;1:连通

public int count; //图G的最大团个数

public int maxclique(int nn,int[][] aa){

n=nn;

a=aa;

x=new int[n+1];

bestx=x;

cn=0;

bestn=0;

count=0;

backtrack(1);

return bestn;

}

public void backtrack(int i){

if(i>n){

for(int j=1;j<=n;j++){

bestx[j]=x[j];

System.out.print(x[j]+" ");

}

System.out.println();

bestn=cn;

count++;

return;

}

else{

boolean ok=true;

for(int j=1;j<i;j++){

if(x[j]==1&&a[i][j]==0){

ok=false;

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);

}

}

}

 

public static void main(String[] args) {

//邻接矩阵a的下标从1开始

int[][] a={

{-1,-1,-1,-1,-1,-1},

{-1, 0, 1, 0, 1, 1},

{-1, 1, 0, 1, 0, 1},

{-1, 0, 1, 0, 0, 1},

{-1, 1, 0, 0, 0, 1},

{-1, 1, 1, 1, 1, 0}};

int n=5;

Maxclique m=new Maxclique();

System.out.println("图G的最大团解向量为:");

System.out.println("图G的最大团顶点数为:"+m.maxclique(n, a));

System.out.println("图G的最大团个为:"+m.count);

}

}
View Code
原文地址:https://www.cnblogs.com/handsometaoa/p/14129998.html