1、极大团:
一个图G = (V,E),要求选取一个子图,这个图中的任意两个点都能相互到达,当这个子图的顶点数最多时,
这个图就是图G的极大团。
2、求解方法:
Born_Kerbosch算法:
(1)规定三个集合:
R:极大团中所包含的顶点;
P:未被匹配,还有可能加入极大团的点;
X:已经被其他极大团匹配过的点,就是已经计数过的点,用于判断重复的极大团;
(2)然后我们找到这三个集合之间的关系:
如果集合P,X都为空集,此时,R一定是一个最大团;
因为如果集合P不为空集,说明P中还有点可以进入极大团;
如果集合X不为空集,说明X中还有已经计数过的点,这些点必然与R中的点相邻(之前判断过),
所以这些点也有可能进入极大团。
所以可以用dfs搜索所有的点,然后不断更新集合P,X,将新的点加入集合R,求出极大团。
(3)对dfs的详解&优化:
因为每次选取的点都是集合P与集合X的交集Z,所以可以从Z中任意选取一点u,
递归查找包含u的极大团,然后选取与u不相邻的点v,因为每次选取v就相当于选取了所有与v相邻的点,
然后递归查找到包含点v的极大团,所以要求u,v两点之间不相邻,这样可以避免重复查找。
递归查找极大团时,每次找到一个新的节点就要更新集合P,集合X,
所以更新集合P = 集合P中所有与u相连的点;
更新集合X = 集合X中所有与u相连的点;
如果找到集合P = 空集,集合X = 空集,就说明找到了一个极大团,结束查找。
3、题目:
说了这么多还是上代码吧:
poj 2989 (查找极大团的数量)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1005;
int R[maxn][maxn],P[maxn][maxn],X[maxn][maxn],mp[maxn][maxn],n,m,ans;
bool dfs(int d,int rn,int pn,int xn){
if(pn==0&&xn==0){
ans++;
if(ans>1000) return 1; //判断是否到达1000的最大值,是否用进行回溯统计下一个极大团
return 0;
}
int u = P[d][0];//取出P中的一个点
for(int i=0;i<pn;i++){
int v = P[d][i];
if(mp[u][v]==1) continue;//找与u不相连的点,因为相连的点都在一个极大团里
for(int j=0;j<rn;j++)
R[d+1][j] = R[d][j];
R[d+1][rn] = v; //将新点加入极大团
int tpn = 0,txn = 0;
for(int j=0;j<pn;j++)
if(mp[v][P[d][j]]) P[d+1][tpn++] = P[d][j]; //更新集合P,记录P与v的交集
for(int j=0;j<xn;j++)
if(mp[v][X[d][j]]) X[d+1][txn++] = X[d][j]; //更新集合X,记录X与v的交集
if(dfs(d+1,rn+1,tpn,txn))
return 1;
P[d][i] = 0;X[d][xn++] = v; //删除原来的v的记录,将完成极大团的点加入X集合
}
return 0;
}
int main(void){
while(~scanf("%d%d",&n,&m)){
memset(mp,0,sizeof(mp));
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
mp[x][y] = mp[y][x] = 1;
}
ans = 0;
for(int i=0;i<n;i++) P[0][i] = i+1;
dfs(0,0,n,0);
if(ans>1000) printf("Too many maximal sets of friends.\n");
else printf("%d\n",ans);
}
return 0;
}
Hdu 1530 (查找极大团最多有多少个节点)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 55;
int mp[maxn][maxn],P[maxn][maxn],R[maxn][maxn],X[maxn][maxn],n,ans;
void dfs(int d,int rn,int pn,int xn){
if(!pn&&!xn){
ans = max(ans,rn);
return ;
}
int u = P[d][0];
for(int i=0;i<pn;i++){
int v = P[d][i];
if(mp[u][v]==1) continue;
for(int j=0;j<rn;j++)
R[d+1][j] = R[d][j];
R[d+1][rn] = v;
int tpn = 0,txn = 0;
for(int j=0;j<pn;j++)
if(mp[v][P[d][j]]==1)
P[d+1][tpn++] = P[d][j];
for(int j=0;j<xn;j++)
if(mp[v][X[d][j]]==1)
X[d+1][txn++] = X[d][j];
dfs(d+1,rn+1,tpn,txn);
P[d][i] = 0;X[d][xn++] = v;
}
}
int main(void){
while(~scanf("%d",&n)&&n){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]);
ans = 0;
for(int i=0;i<n;i++) P[0][i] = i+1;
dfs(0,0,n,0);
printf("%d\n",ans);
}
return 0;
}
4、参考文章: