最大团,极大团

       对于给定图G=(V,E)。其中,V={1,…,n}是图G的顶点集,E是图G的边集。图G的团就是一个两两之间有边的顶点集合。简单地说,团是G的一个完全子图。如果一个团不被其他任一团所包含,即它不是其他任一团的真子集,则称该团为图G的极大团(maximal clique)。顶点最多的极大团,称之为图G的最大团(maximum clique)。最大团问题的目标就是要找到给定图的最大团。

 

一、最大团

       给定无向图G=(V,E),其中V是非空集合,称为顶点集;E是V中元素构成的无序二元组的集合,称为边集,无向图中的边均是顶点的无序对,无序对常用圆括号“( )”表示。如果UV,且对任意两个顶点u,v∈U有(u,v)∈E,则称U是G的完全子图。G的完全子图U是G的团。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'的最大独立集。
通俗点讲就是在一个无向图中找出一个点数最多的完全图
 
二、回溯法求最大团问题
       回溯法搜索解空间树时,根节点首先成为一个活结点,同时也成为当前的扩展节点。在当前扩展节点处,搜索向纵深方向移至一个新节点。这个新节点就成为一个新的活结点,并成为当前扩展节点。如果当前扩展节点不能再向纵深方向移动,则当前的扩展节点就成为死结点。此时,往回回溯至最近的一个活节点处,并使这个活结点成为当前的扩展节点。
回溯法以这种方式递归地在解空间中搜索,直至找到所有要求的解或解空间已无活结点为止。
搜索:
回溯法从根结点出发,按深度优先策略遍历解空间树,搜索满足约束条件的解。
剪枝:
       在搜索至树中任一结点时,先判断该结点对应的部分解是否满足约束条件,或者是否超出目标函数的界;也即判断该结点是否包含问题的解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即剪枝(Pruning);否则,进入以该结点为根的子树,继续按照深度优先的策略搜索。
 
一般来讲,回溯法求解问题的基本步骤如下:
        (1)针对所给问题,定义问题的解空间;确定易于搜索的解空间结构;以深度优先方式搜索解空间,并在搜索过程中利用Pruning函数剪去无效的搜索。
        (2)无向图G的最大团问题可以看作是图G的顶点集V的子集选取问题。因此可以用子集树表示问题的解空间。设当前扩展节点Z位于解空间树的第i层。在进入左子树前,必须确认从顶点i到已入选的顶点集中每一个顶点都有边相连。在进入右子树之前,必须确认还有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。 
        (3)用邻接矩阵表示图GnG的顶点数,cn存储当前团的顶点数,bestn存储最大团的顶点数。cn+n-i为进入右子树的上界函数,当cn+n-i<bestn时,不能在右子树中找到更大的团,利用剪枝函数可将Z的右结点剪去。
 
(就不举例了。想看例子,百度百科。orz....第一次觉得百度讲的东西还有点点清楚。
 
三、例题
1.hdoj1530 Maximum Clique
题意:给定N个点的无向图,让你求最大团。(最大团代码模板)
 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm> 
 4 #define maxn 55
 5 using namespace std;
 6 int A[maxn][maxn],V[maxn];
 7 int cn,bestn;  //当前节点数,最大节点数
 8 int n;
 9 int check(int x){
10     for (int i=1;i<x;i++){
11         if (V[i] && !A[x][i]) return 0;
12     }
13     return 1;
14 }
15 void dfs(int x){
16     if (x>n){  //此处记录最大团 
17         bestn=max(cn,bestn);
18         return ;
19     }
20     if (check(x)){
21         cn++;
22         V[x]=1;
23         dfs(x+1);
24         cn--;
25     }
26     if (cn+n-x>bestn){
27         V[x]=0;
28         dfs(x+1);
29     }
30 }
31 int main(){
32     ios::sync_with_stdio(false);
33     cin.tie(0);cout.tie(0);
34     while (cin >> n && n){
35         for (int i=1;i<=n;i++){
36             for (int j=1;j<=n;j++) cin >> A[i][j];
37         }
38         cn=bestn=0;
39         memset(V,0,sizeof(V));
40         dfs(1);
41         cout << bestn << endl;
42     }
43     return 0;
44 }

 

posted @ 2018-02-16 21:43  Changer-qyz  阅读(4528)  评论(0编辑  收藏  举报