无向图最大团/最大独立集

定义:

团:从一个无向图中找出一个点集,使得此集合中任意两个点都有一条直接相连的边。

极大团:不是任何其他团的子图的团

最大团:极大团中点数最多的团

定理:

一个图的最大独立集等于其补图的最大团


Born_Kerbosch算法

从后往前枚举每一个点为第一个点,选择的其他点为大于这个点的情况。用vec[]记录当前选择的点的集合,判断一个点是否可以选择,只需要枚举已选择的点是否都与之直接相连。

优化: 用num[]记录每个点往后的最优情况(最大团大小),如果最优情况加上当前点数量都不能比已有答案ans更优,直接return。

#include<bits/stdc++.h>
using namespace std;
const int maxn=53;
int mp[maxn][maxn];
int ans_vec[maxn],vec[maxn],num[maxn];//num最后是递减的
    //答案团,当前团,每个位置开始遍历得到的最大团
int n,ans;
int dfs(int p,int siz){
    for(int i=p+1;i<=n;i++){//从前往后遍历每个点
        if(num[i]+siz<=ans)return 0;//最优性剪枝
        if(mp[p][i]){
            int can=1;
            for(int j=1;j<=siz;j++){
                if(!mp[vec[j]][i]){
                    can=0;break;
                }
            }
            if(can){//如果和已有集合均有边,则加入集合
                vec[siz+1]=i;
                if(dfs(i,siz+1))return 1;//更优的答案已经记录,无需更新
            }
        }
    }
    if(siz>ans){
        ans=siz;
        for(int i=1;i<=ans;i++)ans_vec[i]=vec[i];
        return 1;
    }
    return 0;
}
int deal(){
    ans=-1;
    for(int i=n;i>=1;i--){
        vec[1]=i;//开始只有i
        dfs(i,1);
        num[i]=ans;
    }
    return ans;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&mp[i][j]);
        }
    }
    int res=deal();
    printf("%d
",res);
}

更快更短的写法:

#include <bits/stdc++.h>
using namespace std;
const int N = 45;
int n, k, g[N][N], ans[N], answer;
void dfs(int sum, int v[], int len) {
	answer = max(answer, sum);
	int v1[N], len1;
	for(int i = 1; i <= len; ++i) {
		if(sum + len - i + 1 <= answer) break;
		if(sum + ans[v[i]] <= answer) break;//最优性剪枝
		len1 = 0;
		for(int j = i + 1; j <= len; ++j) if(g[v[i]][v[j]]) v1[++len1] = v[j];
		dfs(sum + 1, v1, len1);
	}
} 
inline void MaxClique() {
	int valid[N], len;
	answer = ans[n] = 1;
	for(int i = n - 1; i >= 1; --i) {
		len = 0;
		for(int j = i + 1; j <= n; ++j) if(g[i][j]) valid[++len] = j;
		dfs(1, valid, len);
		ans[i] = answer;
	}
}
int main() {
	scanf("%d%d", &n, &k);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			scanf("%d", &g[i][j]);
	MaxClique();
	printf("%d
",answer);
	return 0;
}
原文地址:https://www.cnblogs.com/ucprer/p/12006019.html