先看一下最大团问题:
其中,形式参数t表示第t个顶点,Place(t)用来判断第t个顶点能否放入团里。二维数组a[][]是图的邻接矩阵。一维数组x[]记录当前解。搜索到第t层时,从第1 个顶点用第t-1个顶点的状态存放入在x[1:t-1]中;一维数组best记录当前最优解,变量cn,bestcn分别记录当前已包含在团里面的顶点个数和当前最优解包含在团里面的顶点个数,初始化都为0。
最大独立集:一个点数最多的点集,且满足集合内的点互不干扰。
最大独立集=补图中的最大团数
方法一:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int maxx=1005;
const int inf=0x3f3f3f3f;
int x[maxx];
int ans;
int e[maxx][maxx];
int n,m,G;
int cn;
int best[maxx];
int bestcn;
void init(){
cn=0;
bestcn=0;
ans=0;
memset(best,0,sizeof(best));
memset(x,0,sizeof(x));
memset(e,1,sizeof(e));//注意这里
}
int place(int t){
for(int i=1;i<=t-1;i++){
if(x[i]&&e[t][i]==0){
return 0;
}
}
return 1;
}
void dfs(int t){
if(t>n){
for(int i=1;i<=n;i++){
best[i]=x[i];
}
bestcn=cn;
return ;
}
if(place(t)){
cn++;
x[t]=1;
dfs(t+1);
cn--;
}
if(cn+n-t>bestcn){
x[t]=0;
dfs(t+1);
}
}
int main(){
int count=1;
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
init();
for(int i=1;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
e[a][b]=e[b][a]=0;
}
dfs(1);
cout<<bestcn<<endl;
for(int i=1;i<=n;i++){
if(best[i]==1){
cout<<i<<" ";
}
}
cout<<endl;
}
return 0;
}
方法二:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int maxx=1005;
const int inf=0x3f3f3f3f;
//ans表示最大团,cnt[N]表示当前最大团的节点数,group[N]用以寻找一个最大团集合
//u为当从前顶点开始深搜,pos为深搜深度(即当前深搜树所在第几层的位置)
int group[maxx];
int cnt[maxx];
int ans;
int pos,n,m;
int e[maxx][maxx];
int vis[maxx];
void init(){
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
memset(group,0,sizeof(group));
memset(e,1,sizeof(e));
}
int dfs(int u,int pos){
for(int i=u+1;i<=n;i++){//按递增顺序枚举顶点
if(cnt[i]+pos<=ans){
return 0;//剪枝
}
if(e[u][i]){
int j;
// 与目前团中元素比较,取 Non-N(i)
for(j=0;j<pos;j++){
if(!e[i][vis[j]]){
break;
}
}
// 若为空,则皆与 i 相邻,则此时将i加入到 最大团中
//深搜层次也就是最大团的顶点数目,vis[pos] = i表示当前第pos小的最大团元素为i(因为是按增顺序枚举顶点 )
if(j==pos){
vis[pos]=i;
if(dfs(i,pos+1)){
return 1;
}
}
}
}
if(pos>ans){
for(int i=0;i<pos;i++){
group[i]=vis[i];// 更新最大团元素
}
ans=pos;
return 1;
}
return 0;
}
void Bron_Kerbosch(){
ans=-1;
for(int i=n;i>=1;i--){
vis[0]=i;
dfs(i,1);
cnt[i]=ans;
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&m);
init();
for(int i=1;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
e[a][b]=e[b][a]=0;
}
//相邻顶点间有边相连,模型转换成求 无向图 最大独立集。
//要求原图的最大独立集,转化为求原图的补图的最大团(最大团顶点数量 = 补图的最大独立集)
Bron_Kerbosch();
cout<<ans<<endl;
for(int i=0;i<n;i++){
if(group[i]!=0)
cout<<group[i]<<" ";
}
cout<<endl;
}
return 0;
}
从时间上看,两个算法的时间复杂度相差不是很大,但是当输入量变多时,两个方法的时间复杂度将非常的明显!