TOP > グラフ
最大クリーク(Maximum-Clique)
説明
グラフの最大クリークを求める。一般グラフに対する最大クリークを求める問題はNP困難である。
補グラフに対する最大独立集合問題と等価である。
計算量
- $O(2^{\sqrt {2M}} N)$
実装例
- maximum_clique($g$, $f$):= 隣接行列 $g$ で表されるグラフのクリークを全列挙する。$f$ がクリークごとに呼び出され, そのとき渡されるvectorにはそのクリークを構成する頂点が格納されている。最終的に $f$ の戻り値のmaxが返される(verifyコード参照)。
template< typename T >
T maximum_clique(Matrix< bool > g, function< T(vector< int >) > f) {
int N = (int) g.size(), M = 0;
vector< int > deg(N), v(N);
for(int i = 0; i < N; i++) {
for(int j = 0; j < i; j++) {
assert(g[i][j] == g[j][i]);
if(g[i][j]) {
++deg[i];
++M;
}
}
}
T t = 0;
int lim = (int) sqrt(2 * M);
for(int i = 0; i < N; i++) {
vector< int > notice;
for(int j = 0; j < N; j++) {
if(!v[j] && deg[j] < lim) {
for(int k = 0; k < N; k++) {
if(j == k) continue;
if(g[j][k]) notice.emplace_back(k);
}
notice.emplace_back(j);
break;
}
}
if(notice.empty()) break;
int neighbor = (int) notice.size() - 1;
vector< int > bit(neighbor);
for(int j = 0; j < neighbor; j++) {
for(int k = 0; k < j; k++) {
if(!g[notice[j]][notice[k]]) {
bit[j] |= 1 << k;
bit[k] |= 1 << j;
}
}
}
for(int j = 0; j < (1 << neighbor); j++) {
bool ok = true;
for(int k = 0; k < neighbor; k++) {
if((j >> k) & 1) ok &= (j & bit[k]) == 0;
}
if(ok) {
vector< int > stock{notice.back()};
for(int k = 0; k < neighbor; k++) {
if((j >> k) & 1) stock.emplace_back(notice[k]);
}
t = max(t, f(stock));
}
}
v[notice.back()] = true;
for(int j = 0; j < N; j++) {
if(g[j][notice.back()]) {
--deg[j];
g[notice.back()][j] = g[j][notice.back()] = false;
}
}
}
vector< int > notice;
for(int j = 0; j < N; j++) {
if(!v[j]) notice.emplace_back(j);
}
int neighbor = (int) notice.size();
vector< int > bit(neighbor);
for(int j = 0; j < neighbor; j++) {
for(int k = 0; k < j; k++) {
if(!g[notice[j]][notice[k]]) {
bit[j] |= 1 << k;
bit[k] |= 1 << j;
}
}
}
for(int j = 0; j < (1 << neighbor); j++) {
bool ok = true;
for(int k = 0; k < neighbor; k++) {
if((j >> k) & 1) ok &= (j & bit[k]) == 0;
}
if(ok) {
vector< int > stock;
for(int k = 0; k < neighbor; k++) {
if((j >> k) & 1) stock.emplace_back(notice[k]);
}
t = max(t, f(stock));
}
}
return t;
}
検証
AtCoder Beginner Contest 002 D - 派閥
int main() {
int N, M;
cin >> N >> M;
Matrix< bool > g(N, vector< bool >(N));
for(int i = 0; i < M; i++) {
int x, y;
cin >> x >> y;
--x, --y;
g[x][y] = true;
g[y][x] = true;
}
function< int(vector< int >) > f = [](vector< int > t) { return t.size(); };
cout << maximum_clique(g, f) << endl;
}
int main() {
int N, M;
cin >> N >> M;
Matrix< bool > g(N, vector< bool >(N));
Matrix< int > h(N, vector< int >(N));
for(int i = 0; i < M; i++) {
int x, y, z;
cin >> x >> y >> z;
--x, --y;
g[x][y] = true;
g[y][x] = true;
h[x][y] = z;
h[y][x] = z;
}
function< int(vector< int >) > f = [&](vector< int > t) {
if(t.size() <= 1) return 0;
int ret = 0;
for(int i = 0; i < t.size(); i++) {
int uku = 1 << 30;
for(int j = 0; j < t.size(); j++) if(i != j) uku = min(uku, h[t[i]][t[j]]);
ret += uku;
}
return ret;
};
cout << maximum_clique(g, f) << endl;
}