现在的位置: 首页 > 综合 > 正文

hdu 2444 The Accomodation of Students (交叉染色+二分匹配)

2018年02月18日 ⁄ 综合 ⁄ 共 1329字 ⁄ 字号 评论关闭

题目链接:   hdu 2444

题目大意:   给出N个人和M对关系,表示a和b认识

                  把N个人分成两组,同组间任意俩人互不认识

                  若不能分成两组输出No,否则输出两组间俩人互相认识的对数

解题思路:   先判断能否构成二分图,判断二分图用交叉染色法

                  从某个未染色的点出发把此点染成白色,该点周围的点染成黑色

                  黑色周围的又染成白色,若走到某个点已经染色

                  并且它相邻点的颜色与它一样则不是二分图,而是有奇数圈的图

                  可以这样理解,染白色既加入X集合,黑色既加入Y集合

                  若某个点即是X集合又是Y集合,那说明不是二分图

                  判断二分图之后,再求最大的匹配数

                  PS:二分图是无向图时最大匹配数是Sum/2,因为算多了一倍

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 250
int n,m,pd,sum,edge[MAX][MAX],Map[MAX][MAX],Colors[MAX],cx[MAX],cy[MAX],visit[MAX];

void Color(int u,int color)  //交叉染色判断二分图
{
    if(pd==1)
        return ;
    int i;
    for(i=1;i<=n;i++)
    {
        if(Map[u][i])
        {
             if(Colors[i]==-1)
            {
                sum++;
                 Colors[i]=(!color);
                Color(i,!color);
            }
            else if(i!=u&&Colors[i]==color&&Colors[i]!=-1)
            {
                pd=1;
                return ;
            }
        }
    }
}

int DFS(int u)     //匈牙利最大匹配
{
    int i;
    for(i=1;i<=n;i++)
    {
        if(Map[u][i]&&!visit[i])
        {
            visit[i]=1;
            if(!cy[i]||DFS(cy[i]))
            {
                cy[i]=u;
                cx[u]=i;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    int i,j,k,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        pd=sum=0;
        memset(cx,0,sizeof(cx));
        memset(cy,0,sizeof(cy));
        memset(Map,0,sizeof(Map));
        memset(Colors,-1,sizeof(Colors));
        memset(visit,0,sizeof(visit));
        memset(edge,0,sizeof(edge));
        for(i=1;i<=m;i++)     //双向边
        {
            scanf("%d%d",&a,&b);
            Map[a][b]=Map[b][a]=1;
        }
        Colors[1]=0;
        sum=1;
        Color(1,0);
        if(pd)
            printf("No\n");
        else
        {
            for(i=1,sum=0;i<=n;i++)
            {
                if(!cx[i])
                {
                    memset(visit,0,sizeof(visit));
                    sum+=DFS(i);
                }
            }
            printf("%d\n",sum/2);   //一半
        }
    }
}

抱歉!评论已关闭.