题意:给出n个人,其中m对朋友,求极大团数量(若超过1000则输出“Too many maximal sets of friends.”)。
思路:
1)定义:一个点集S被称为极大团,当且仅当S中的所有点均互为朋友,且所有不在S中的人,均与S中的某些人不是朋友。
2)算法:Bron-Kerbosch算法(DFS)
wiki上的伪代码,其中All是已经选的点集,Some是还未选的,None是已经搜过的(避免重复,其实就是不能选的)
N(v)指与v的朋友(相邻点)
BronKerbosch(All, Some, None):
if Some and None are both empty:
report All as a maximal clique //所有点已选完,且没有不能选的点,累加答案
for each vertex v in Some: //枚举Some中的每一个元素
BronKerbosch1(All ⋃ {v}, Some ⋂ N(v), None ⋂ N(v))
//将v加入All,显然只有与v为朋友的人才能作为备选,None中也只有与v为朋友的才会对接下来造成影响
Some := Some - {v} //已经搜过,在Some中删除,加入None
None := None ⋃ {v}
3)小优化:
设key = some[1],则仅当key与v不为朋友时,才需要枚举v,因为此时与v相关的必定已被搜过(与None同理,但可以大大加速)
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#define For(i,j,k) for(int i = j;i <= (int)k;i ++)
#define Set(i,j) memset(i, j, sizeof(i))
using namespace std;
const int N = 130;
int Ans, G[N][N], all[N][N], some[N][N], none[N][N];
void DFS(int n, int an, int sn, int nn){
if(!sn && !nn) Ans++;
if(Ans > 1000) return;
int key = some[n][1];
For(j,1,sn){
int v = some[n][j], tsn = 0, tnn = 0;
if(G[key][v])continue;
For(i,1,an) all[n+1][i] = all[n][i]; all[n+1][an+1] = v;
For(i,1,sn) if(G[v][some[n][i]]) some[n+1][++tsn] = some[n][i];
For(i,1,nn) if(G[v][none[n][i]]) none[n+1][++tnn] = none[n][i];
DFS(n + 1, an + 1, tsn, tnn);
some[n][j] = 0, none[n][++nn] = v;
}
}
int main(){
int n, m;
while(scanf("%d%d", &n, &m) == 2){
int x, y;
Set(G, 0), Ans = 0;
For(i,1,m){
scanf("%d%d", &x, &y);
G[x][y] = G[y][x] = 1;
}
For(i,1,n) some[1][i] = i;
DFS(1, 0, n, 0);
if(Ans > 1000) puts("Too many maximal sets of friends.");
else printf("%d\n", Ans);
}
return 0;
}