最大团问题-分支限界
问题描述:
给定无向图G=(V, E),其中V是非空集合,称为顶点集;
E是V中元素构成的无序二元组的集合,称为边集,无向图中的边均是顶点的无序对,无序对常用圆括号“( )”表示。
如果U∈V,且对任意两个顶点u,v∈U有(u, v)∈E,则称U是G的完全子图。
G的完全子图U是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'的最大独立集。
问题定义:
解空间树中结点类型:bbnode
活结点优先队列中元素类型为 CliqueNode(cn 表示与该节点相应的团的定点数,un表示结点为根的子树中的最大顶点树的上界。level表示结点在子集空间树中所处的层次;ch 左右儿子的结点标记)
ch=1 左儿子 ch=0 右儿子
ptr 指向解空间树中相应结点的指针
cn+n-level+1表示定点数上界的un值。
代码描述:
相关结构体定义:
class bbnode{
friend class Clique;
private:
bbnode * parent;
bool LChild;
};
class CliqueNode{
friend class Clique;
public:
operator int () const {return un;}
private:
int cn,
un,
level;
bbnode *ptr;
};
class Clique{
friend void main(void);
public:
int BBMaxClique(int []);
private:
void AddLiveNode(MaxHeap<CliqueNode> &H,int cn,int un,int level,bbnode E[],bool ch);
int * * a ,n;
};
AddLiveNode:将当前构造的活结点 加入到子集空间树中并插入活结点优先队列中。
void Clique::AddLiveNode(MaxHeap<CliqueNode> &H,int cn,int un,int level,bbnode E[],bool ch)
{
bbnode * b = new bbnode;
b->parent = E;
b->LChild = ch;
CliqueNode N;
N.cn = cn;
N.level = level;
N.un = un;
N.Insert(N);
}
算法核心代码:BBMaxClique
子集树的根节点是 初始扩展结点 cn为0
i 表示当前扩展结点的解空间树中所处的层次。
首先考察左儿子:
顶点加入当前团,检查该顶点与当前团中其他顶点是否有边相连。
都有边,可行,纳入 活结点 优先队列中,AddLiveNode(),接着考察当前扩展结点的 右儿子结点,仅当un>bestn时,右子树中可能含有最优解 ;
否则,不可行。
int Clique::BBMaxClique(int bestx[])
{
MaxHeap<CliqueNode> H(1000);
bbnode * E = 0;
int i=1,
cn = 0,
bestn = 0;
while(i != n+1)
{
bool OK = true;
bbnode * B = E;
for(int j = i-1;j>0;B=B->parent,j--)
{
if(B->LChild && a[i][j]==0)
{
OK = false;
break;
}
}
if(OK)
{
if(cn + 1 > bestn)
bestn = cn + 1;
AddLiveNode(H,cn+1,cn+n-i+1,i+1,E,true);
}
if(cn+n-i >= bestn)
AddLiveNode(H,cn+1,cn+n-i+1,i+1,E,true);
CliqueNode N;
H.DeleteMax(N);
E = N.ptr;
cn = N.cn;
i = N.level;
}
for(int j=n;j>0;j--)
{
bestx[j] = E->LChild;
E = E->parent;
}
return bestn;
}
- 认识createDocumentFragment
- 点击穿透原理及解决
- 如何使用Intellij搭建Spark开发环境
- 如何重置Cloudera Manager的admin密码
- 如何在CDH集群安装Anaconda&搭建Python私有源
- 如何使用Python Impyla客户端连接Hive和Impala
- 如何在Windows Server2008搭建DNS服务并配置泛域名解析
- 如何通过CM API优雅的获取元数据库密码
- CM启动报InnoDB engine not found分析
- 如何在Hue中使用Sentry
- 如何在Redhat中配置R环境
- 如何在Redhat中安装R的包及搭建R的私有源
- 什么是sparklyr
- 如何利用Dnsmasq构建小型集群的本地DNS服务器
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Tree - 337. House Robber III
- Tree - 250. Count Univalue Subtrees
- Tree - 124. Binary Tree Maximum Path Sum
- Tree - 110. Balanced Binary Tree
- Tree - 104. Maximum Depth of Binary Tree
- Tree - 298. Binary Tree Longest Consecutive Sequence
- Tree - 111. Minimum Depth of Binary Tree
- Tree - 129. Sum Root to Leaf Numbers
- Tree - 113. Path Sum II
- DFS&BFS - 200. Number of Islands
- Backtracking - 93. Restore IP Addresses
- Backtracking - 17. Letter Combinations of a Phone Number
- Backtracking - 60. Permutation Sequence
- Backtracking - 47. Permutations II
- Backtracking - 46. Permutations