求图中的最大独立集或最大团(UVA 193)

41 篇文章 0 订阅

几个概念

  • 完全图:简单无向图,图中的任意两个点之间有且仅有一条边相连,所有完全图都是它本身的团。
  • 补图:图G的补图通俗的来讲就是完全图Kn去除G的边集后得到的图Kn-G。
  • 团(clique):顶点集C被称为无向图 G=(V,E) 的团,如果C是顶点集V的子集(C⊆V),而且任意两个C中的顶点都有边连接。
  • 最大团:最大完全子图。
  • 最大团中顶点数量 = 补图的最大独立集中顶点数量(可反正)

dfs时的几个剪枝

  • 有序枚举,枚举i时只考虑其后面的点。
  • nun[i]表示只考虑i~n号点时的最大团大小,ans为当前最优值,假设当前枚举x连出的点,i>x,若num[i]+1<=ans,则i ~ n都没有枚举的必要了,因为不可能更新最大值。
  • 枚举i为顶点时,开始ans的值为num[i+1],当成功更新ans时,ans=num[i+1]+1,此时已没有必要枚举i ~ n的最大团,可以直接return。

Bron-Kerbosch算法

  • 基础形式是一个递归回溯的搜索算法.通过给定三个集合 (R,P,X).
  • 初始化集合R,X分别为空,而集合P为所有顶点的集合.
  • 而每次从集合P中取顶点{v}, 当集合中没有顶点时,两种情况.
  • 集合 R 是最大团, 此时集合X为空.
  • 无最大团,此时回溯.
  • 对于每一个从集合P中取得得顶点{v},有如下处理:
  • 1.将顶点{v}加到集合R中, 集合P,X 与 顶点{v}得邻接顶点集合 N{v}相交, 之后递归集合 R,P,X.
  • 2.从集合P中删除顶点{v},并将顶点{v}添加到集合X中.若 集合 P,X都为空, 则集合R即为最大团.
  • 总的来看就是每次从 集合P中取v后,再在 P∩N{v} 集合中取,一直取相邻,保证集合R中任意顶点间都两两相邻…
    UVA 193
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <fstream>
using namespace std;
int m,n,k,ans;
bool maps[105][105],rmap[105][105];
int cnt[105],vis[105],group[105];//cnt[i]表示包含i...n的点的图的补图中最大团的大小
bool dfs(int u,int pos)//vis[0~pos-1]表示当前正在求的团中的点
{
    int i,j;
    for(i=u+1;i<=n;i++)
    {
        if(cnt[i]+pos<=ans)
            return 0;
        if(rmap[u][i])
        {
            for(j=0;j<pos;j++) if(!rmap[i][vis[j]]) break;
            if(j==pos)
            {
                vis[pos]=i;
                if(dfs(i,pos+1)) return 1;
            }
        }
    }
    if(pos>ans)
    {
        ans=pos;
        for(i=0;i<pos;i++)
        group[i]=vis[i];
        return 1;
    }
    return 0;
}
int BK()
{
    ans=-1;
    for(int i=n;i>=1;i--)
    {
        vis[0]=i;
        dfs(i,1);
        cnt[i]=ans;
    }
    return ans;
}
int main()
{
    freopen("1.txt","w",stdout);
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d%d",&n,&k);
        memset(rmap,1,sizeof(rmap));
        memset(maps,0,sizeof(maps));
        memset(group,0,sizeof(group));
        for(int i=1;i<=k;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            maps[u][v]=maps[v][u]=1;
            rmap[u][v]=rmap[v][u]=0;
        }
        cout<<BK()<<endl;
        sort(group,group+ans);
        cout<<group[0];
        for(int i=1;i<ans;i++)
        cout<<' '<<group[i];
        cout<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈希表扁豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值