题目链接:http://poj.org/problem?id=2989
分析
这道题求的是极大团的个数,可以用Bron-Kerbosch算法。以下是我对该算法的个人理解,不对之处,欢迎指正。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define For(i,j,k) for(int i = j; i <= k; i++)
#define N 130
int a[N][N],all[N][N],some[N][N],none[N][N];
int ans;
void dfs(int n,int an,int sn,int nn)
{
if(!sn && !nn) ans++;//所有点已选完,且没有不能选的点
if(ans > 1000) return;
int u = some[n][1];
For(i,1,sn) {//枚举some中的每一个元素
int v = some[n][i],tsn = 0,tnn = 0;
if(a[u][v]) continue;//与v相关的点之前已经被搜索过
For(j,1,an) all[n + 1][j] = all[n][j];//复制一份
all[n + 1][an + 1] = v;//将v加入新的集合当中
//some中只有与v有联系的点才能作为备选,none中也只有与v有联系的点才会对接下来造成影响
For(j,1,sn) if(a[v][some[n][j]]) some[n + 1][++tsn] = some[n][j];
For(j,1,nn) if(a[v][none[n][j]]) none[n + 1][++tnn] = none[n][j];
dfs(n + 1,an + 1,tsn,tnn);//All ⋃ {v}, Some ⋂ N(v), None ⋂ N(v)
//N(v):结点v的所有直接邻居(有边直接相连)结点的集合
some[n][i] = 0,none[n][++nn] = v;//在some中删除v,none中加入v,关于这个点的所有极大团已经找到,之后与v相关的极大团就不会再次计入
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)) {
memset(a,0,sizeof(a));
memset(all,0,sizeof(all));
memset(some,0,sizeof(some));
memset(none,0,sizeof(none));
ans = 0;
int u,v;
For(i,1,m) {
scanf("%d%d",&u,&v);
a[u][v] = a[v][u] = 1;
}
For(i,1,n) some[1][i] = i;
dfs(1,0,n,0);
if(ans > 1000) printf("Too many maximal sets of friends.\n");
else printf("%d\n",ans);
}
return 0;
}