极大团:无法从图中再加入一个顶点使得此顶点集的顶点两两相连的顶点集

因此单个顶点也可能是一个极大团

最大团:一个包含顶点数最多的极大团

最大独立集=补图的最大团

定理:最大独立集=补图的最大团,最大团=补图的最大独立集

Bron-kerbosch模板

说明

all-已取顶点集,some-未处理顶点集(初始状态是全部顶点),none-不取的顶点集,g-边,
S-极大团数量,ans-最大团结点数;
结点编号1~n,0用于辅助,表示被删除;
求最大团顶点数时只要some;要求记录路径时要all;
求极大团数量要some、none;要求记录路径时要all;

极大团计数

输入:some,g;
输出:S;
调用方法:dfs(0,0,n,0);
some的初始化:for(int I=0; I<n; ++I) some[0][I]=I+1;
复杂度爆炸,可处理一两百个点

POJ 2989 All friends

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 129;

int n, m;
int S;
int some[N][N], all[N][N], none[N][N], g[N][N];
void dfs(int d, int an, int sn, int nn) {
    if(!sn&&!nn) ++S;
    if(S>1000) return; //题意表明S超过1000就输出Impossible
    int u=some[d][0];
    for(int i=0; i<sn; ++i) {
        int v=some[d][i];
        if(g[u][v]) continue;
        int tsn=0, tnn=0;
        //for(int j=0; j<an; ++j) all[d+1][j]=all[d][j];
        //all[d+1][an]=v;  //可以不写这两行
        for(int j=0; j<sn; ++j) if(g[v][some[d][j]])
            some[d+1][tsn++]=some[d][j];
        for(int j=0; j<nn; ++j) if(g[v][none[d][j]])
            none[d+1][tnn++]=none[d][j];
        dfs(d+1,an+1,tsn,tnn);
        some[d][i]=0, none[d][nn++]=v;
    }
}

int main() {
    ios::sync_with_stdio(false);
    while(cin>>n>>m) {
        S=0;
        memset(g,0,sizeof(g));
        for(int i=0; i<m; ++i) {
            int a, b;
            cin>>a>>b;
            g[a][b]=g[b][a]=1;
        }
        for(int i=0; i<n; ++i) some[0][i]=i+1; //some的初始化
        dfs(0,0,n,0);
        if(S>1000) cout<<"Too many maximal sets of friends."<<endl;
        else cout<<S<<endl;
    }
}

最大团

输入:some,g;
输出:ans,最大团顶点集保存在all[ans]数组的前ans个数,即all[ans][i]
调用方式:dfs(0,n,0);
复杂度依然爆炸,可处理一两百个点

POJ 2989 All friends

#include "bits/stdc++.h"

using namespace std;

const int N = 51;

int n, ans;
int some[N][N], g[N][N];
void dfs(int d, int sn, int an) {
    if(sn+an<=ans) return;
    if(!sn) {
        ans=max(ans,an);
        return;
    }
    int u=some[d][0];
    for(int i=0; i<sn; ++i) {
        int v=some[d][i];
        if(g[u][v]) continue;
        int tsn=0;
        //for(int j=0; j<an; ++j) all[d+1][j]=all[d][j];
        //all[d+1][an]=v;  //这两行代码可以保存最大团顶点集
        for(int j=0; j<sn; ++j) if(g[v][some[d][j]])
            some[d+1][tsn++]=some[d][j];
        dfs(d+1,tsn,an+1);
        some[d][i]=0;
    }
}

int main() {
    ios::sync_with_stdio(false);
    while(cin>>n, n) {
        ans=0;
        memset(g,0,sizeof(g));
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=n; ++j) cin>>g[i][j];
        for(int i=0; i<n; ++i) some[0][i]=i+1;
        dfs(0,n,0);
        cout<<ans<<endl;
    }
}