POJ 1419--Graph Coloring(最大团求二着色问题)

32 篇文章 0 订阅
24 篇文章 0 订阅

  1. 题目要求:无向图G中二着色,也即是求一最大规模点集V‘是V子集,其中任意两点在图中没有边连接,也即是求最大独立集。最大独立集是G的补图的最大团(Max Clique),最大团和最大独立集相反,其中任意两点都有边连接。显然最大独立集中的点在G的补图中都应该连接,这些点集合成一个团。若它不是最大团,假设补图中有一个更大的团,则对其再求补图,可知团中的点在其补图中是不连接的,则是一个规模更大的独立集。
  2. DFS求最大团:参考  http://www.cnblogs.com/zhj5chengfeng/archive/2013/07/29/3224092.html
  • 算法基本思路:把最大团中的点按升序排列,设团集合为v0,v1,......,vk。显然这些点都在相互的邻接表当中,则我们先把v0的邻接点放入集合U0,然后再选出v1在U0中的邻接点放到U1,....,直到Uk的元素个数为0,则深搜回溯。因为不知道v0是图中那个点,所以我们需要遍历从所有点出发的最大团。
  • 遍历的一些技巧:从最大点开始逆序遍历,设cliqueSize[i]为v[i]到v[N]中的点组成的最大团,显然cliqueSize[N] = 1,且cliqueSize[i+1]  <= cliqueSize[i] <= cliqueSize[i+1]+1。
  • 根据以上思路可以得出剪枝的一些技巧
  1. 如果在从vi开始搜索时,maxCliqueSize被更新(只会增加1),因为更新前maxCliqueSize = cliqueSize[i+1],所以再从v[i]出发的团规模不会再增加,可以直接返回从v[i-1]出发再搜索。
  2. 如果剩余点数加上当前团规模小于等于最大团规模,则返回0.
  3. 如果当前团规模加上将要深搜的点已求出的最大团规模小于等于最大团规模,返回0。

#include<cstdio>
#include<cstring>
#define maxN 102

int nodeNum;
int maxCliqueSize;
char g[maxN][maxN];
char blackNode[maxN],tmpBlackNode[maxN];
char cliqueSet[maxN][maxN],cliqueSize[maxN];

int DFS(int adjNum,int tmpCliqueSize)
{
    if(adjNum == 0)
    {
        if(tmpCliqueSize > maxCliqueSize)             //当前团规模为已求得最大团规模加一
        {
            maxCliqueSize = tmpCliqueSize;
            memcpy(blackNode,tmpBlackNode,sizeof(blackNode));
            return 1;
        }
        return 0;
    }
    int i,j;
    int newNode;
    int nextAdjNum;
    for(i = 0;i < adjNum;i++)
    {
        nextAdjNum = 0;
        newNode = cliqueSet[tmpCliqueSize][i];
        if(tmpCliqueSize+adjNum-i <= maxCliqueSize) return 0;            //当前团规模加上剩余点数小于等于已知最大团规模
        if(tmpCliqueSize+cliqueSize[newNode] <= maxCliqueSize) return 0;    //当前团规模加上即将搜索的点的最大团规模小于等于已知所有点最大团规模
        for(j = i+1;j < adjNum;j++)
        {
            if(g[newNode][cliqueSet[tmpCliqueSize][j]])
                cliqueSet[tmpCliqueSize+1][nextAdjNum++] = cliqueSet[tmpCliqueSize][j];
        }
        tmpBlackNode[tmpCliqueSize+1] = newNode;
        if(DFS(nextAdjNum,tmpCliqueSize+1))   return 1;
    }
    return 0;
}

int maxClique()
{
    int i,j;
    int adjNum;
    maxCliqueSize = 0;
    for(i = nodeNum;i >= 1;i--)
    {
        adjNum = 0;
        for(j = i+1;j <= nodeNum;j++)
        {
            if(g[i][j])
            cliqueSet[1][adjNum++] = j;
        }
        tmpBlackNode[1] = i;
        DFS(adjNum,1);
        cliqueSize[i] = maxCliqueSize;
    }
    return 0;
}

int generateGraph(char* str)
{
    int a,b;
    a = b = 0;
    while(*str != ' ')
    {
        a *= 10;
        a += *(str++)-'0';
    }
    while(*(++str))
    {
        b *= 10;
        b += *str-'0';
    }
    g[a][b] = g[b][a] = 0;
    return 0;
}

int main()
{
    int i,T;
    char tmp[10];
    int edgeNum;
    scanf("%d",&T);
    while(T--)
    {
        memset(g,1,sizeof(g));
        scanf("%d%d",&nodeNum,&edgeNum);
        getchar();
        while(edgeNum--)
        {
            gets(tmp);
            generateGraph(tmp);
        }
        maxClique();
        printf("%d\n",maxCliqueSize);
        for(i = 1;i <= maxCliqueSize;i++)
        {
            printf("%d",blackNode[i]);
            if(i != maxCliqueSize) printf(" ");
            else printf("\n");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值