Algorithm 457: Finding All Cliques of an Undirected Graph [H] – Coen Bron* and Joep Kerboscht – Archives of Communication of ACM
原Essay详细而准确地描述了该算法的过程,不需要额外的注解也能轻松理解。若英语阅读吃力,也有一份不错的中文详述:
极大团(maximal clique)算法:Bron-Kerbosch算法 – Bowiee – 简书
下面给出一份参考实现,能够找出所有极大团。使用unsigned long long存储各状态点的集合,二进制表示下从低到高第$(x-1)$位为$1$表示点$x$存在于集合中。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
constexpr int N = 60;
ull e[N]; int n, m, x, y, mxsiz;
vector <ull> max_clique;
#define lowbit(x) (x & -x)
#define popc(x) (__builtin_popcountll (x))
#define log2s(x) (__builtin_ctzll (x))
void Bron_Kerbosch (ull cli /* 团 */,
ull can /* 候选节点 */, ull ban /* 禁选节点 */) {
if (!can && !ban) {
max_clique.push_back (cli);
mxsiz = max (mxsiz, popc (cli));
return;
}
// 准备下一层搜索的各项参数。
ull _cli, _can = can | ban, _ban, l;
int x, pivot, mxnei = -1, tmp;
// 在ban和can集合中,选择合法邻居最多的一个节点作为基准点。
while (_can) {
x = log2s (l = lowbit (_can)) + 1;
tmp = popc (can & e[x]);
if (tmp > mxnei)
mxnei = tmp, pivot = x;
_can ^= l;
}
l = 1ull<<pivot - 1;
// 若该节点来自can,先行搜索。
if (can & l) Bron_Kerbosch (cli | l,
can & e[pivot], ban & e[pivot]), can ^= l;
while (can) {
x = log2s (l = lowbit (can)) + 1;
if (l & e[pivot]) { can ^= l; continue; }
_can = can & e[x];
_cli = cli | l, _ban = ban & e[x];
Bron_Kerbosch (_cli, _can, _ban);
ban |= l, can ^= l;
}
}
int main () {
scanf ("%d%d", &n, &m);
for (int i = 1; i <= m; ++i)
scanf ("%d%d", &x, &y),
e[x] |= 1ull<<y - 1,
e[y] |= 1ull<<x - 1;
Bron_Kerbosch (0, (1ull<<n) - 1, 0);
// 对max_clique作统计。
// ...
return 0;
}
发表回复