最大团问题

最大团问题

首先介绍一些基本概念:

1、什么是团?如果一个子图是一个无向图的完全子图,那么可以称为一个团。

2、什么是极大团?如果一个团不是任何一个团的子集,那么可以称做一个极大团。

3、如果一个极大团的大小是最大的,那么可以被称为一个最大团。

最大团有以下常见性质,这里不加证明的直接给出结论。

最大团点的数量等于其补图中最大独立集的数量(最大团与最大独立集的关系)。特别的,在二分图中,最大独立集=顶点数-最大匹配数。(这个很好理解,因为找到补图中的最大团,在图中这些边都是不存在的,并且是点个数最多的。)

下面给出模板:(HDU 1530)

#include<bits/stdc++.h>

using namespace std;

const int N = 105;

int n, G[N][N];
int cntClique, pts[N], res[N], cnt[N];

bool dfs(int pos, int num){

    for(int i=pos+1;i<=n;++i){
        if(cnt[i]+num<=cntClique)return false;//这里是一处剪枝

        if(G[pos][i]){//考虑与当前团节点的关系
            int ok=1;
            for(int id=1;id<=num;++id){
                if(!G[i][pts[id]]){
                    ok=0;break;
                }
            }

            if(ok){
                pts[num+1]=i;
                if(dfs(i,num+1))return true;
            }
        }
    }

    if(num>cntClique){ //多枚举一个,最多只扩充一个点
        for(int i=1;i<=num;++i){
            res[i]=pts[i];
        }
        cntClique=num;
        return true;
    }

    return false;
}

void maxClique(){
    cntClique=-1;
    for(int i=n;i>0;--i){
        pts[1]=i;
        dfs(i,1);
        cnt[i]=cntClique;
    }
}

int main(){
    while(scanf("%d",&n)&&n){
        memset(G,0,sizeof G);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                scanf("%d",&G[i][j]);
            }
        }

        maxClique();
        printf("%d
",cntClique);
    }
    return 0;
}

POJ(1419)

#include<cstdio>
#include<cstring>

//#include<bits/stdc++.h>

using namespace std;

const int N = 105;

int n, m, G[N][N];
int cntClique, pts[N], res[N], cnt[N];

bool dfs(int pos, int num){

    for(int i=pos+1;i<=n;++i){
        if(cnt[i]+num<=cntClique)return false;//这里是一处剪枝

        if(G[pos][i]){//考虑与当前团节点的关系
            int ok=1;
            for(int id=1;id<=num;++id){
                if(!G[i][pts[id]]){
                    ok=0;break;
                }
            }

            if(ok){
                pts[num+1]=i;
                if(dfs(i,num+1))return true;
            }
        }
    }

    if(num>cntClique){ //多枚举一个,最多只扩充一个点
        for(int i=1;i<=num;++i){
            res[i]=pts[i];
        }
        cntClique=num;
        return true;
    }

    return false;
}

void maxClique(){
    cntClique=-1;
    for(int i=n;i>0;--i){
        pts[1]=i;
        dfs(i,1);
        cnt[i]=cntClique;
    }
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        memset(G,0,sizeof G);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i){
            int u,v;scanf("%d%d",&u,&v);
            G[u][v]=1;G[v][u]=1;
        }

        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                if(i==j)G[i][j]=0;
                else{
                    G[i][j]^=1;
                }
            }
        }

        maxClique();
        printf("%d
",cntClique);
        for(int i=1;i<=cntClique;++i){
            printf("%d ",res[i]);
        }

    }
    return 0;
}

原文地址:https://www.cnblogs.com/JohnRan/p/13220055.html