转载与模板 – Bron-Kerboscht 极大团算法

作者:

在

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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注