「题解」极大团 clique

Posted Lu_Anlai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「题解」极大团 clique相关的知识,希望对你有一定的参考价值。

本文将同步发布于:

题目

题目链接:POJ2989

题意简述

给定一张 \\(n\\) 个点 \\(m\\) 条边的无向图,求极大团的个数。若极大团数超过 \\(10^3\\),输出 Too many maximal sets of friends.

\\(n\\leq 128\\)

题解

极大团的数量是 Bron-Kerbosch 算法的典型应用,套用即可。

算法流程如下:

  • 对于一个图 \\(G\\),我们将它分成四个部分:
    1. 在当前团中的点;
    2. 在当前团的邻域内的点(准备入团)
    3. 在当前邻域内的点(不准备入团,也就是之前统计过的点);
    4. 不在与当前团无边相连的点(不在邻域内的点);
  • 我们每次从第二部分中选择一个点入团,并更新相应的集合;
  • 当第二个集合为空时,我们不能扩大团,为极大团,准备回溯,若此时第三个集合为空,这个团之前并未搜索过,更新当前答案。

上面的方法可以每次找到一个团,但是时间复杂度仍然不够优秀,我们考虑去除重复状态,具体地,我们从第二个集合中选择一个代表点,如果当前点与代表点有边相连,则跳过当前点,因为我们一定会在加入代表点之后决定加入这个点,这样搜索没有改变状态,而减少了搜索的路径。

参考程序

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
inline int read(void){
	reg char ch=getchar();
	reg int res=0;
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) res=10*res+(ch^\'0\'),ch=getchar();
	return res;
}

const int MAXN=128+5;

int n;
bool G[MAXN][MAXN];
unsigned int ans;

inline void dfs(vector<int> bas,vector<int> p,vector<int> n){
	if(ans>1000u)
		return;
	if(!p.size()){
		if(!n.size())
			++ans;
		return;
	}
	reg int pivot=p[0];
	for(reg int i=0,siz=p.size();i<siz;++i){
		int v=p[i];
		if(G[pivot][v])
			continue;
		vector<int> np,nn;
		for(reg int j=0;j<i;++j)
			if(G[pivot][p[j]]&&G[v][p[j]])
				np.push_back(p[j]);
		for(reg int j=i+1;j<siz;++j)
			if(G[v][p[j]])
				np.push_back(p[j]);
		for(int x:n)
			if(G[v][x])
				nn.push_back(x);
		vector<int> nbas=bas;
		nbas.push_back(v);
		dfs(nbas,np,nn);
		if(ans>1000u)
			return;
		n.push_back(v);
	}
	return;
}

int main(void){
	reg int t=read();
	while(t--){
		reg int n=read();
		for(reg int i=0;i<n;++i)
			for(reg int j=0;j<n;++j)
				G[i][j]=false;
		reg int m=read();
		for(reg int i=0;i<m;++i){
			static int x,y;
			x=read()-1,y=read()-1;
			G[x][y]=G[y][x]=true;
		}
		vector<int> U;
		U.resize(n);
		for(reg int i=0;i<n;++i)
			U[i]=i;
		ans=0;
		dfs(vector<int>{},U,vector<int>{});
		if(ans>1000u)
			puts("Too many maximal sets of friends.");
		else
			printf("%u\\n",ans);
	}
	return 0;
}

以上是关于「题解」极大团 clique的主要内容,如果未能解决你的问题,请参考以下文章

HDOJ5952Counting Cliques(团,dfs)

图论-相关概念

HDU5952Counting Cliques

证明CLIQUE(团问题)是NP完全

The Largest Clique UVA - 11324 (有向图最大团)

UVa11324 最大团 The Largest Clique-有向图强连通分量&DP