二分图判定+最大匹配+例题HDU2444 The Accomodation of Students

注:本文参考博客链接二分图大合集

二分图定义:
二分图也称二部图,是图论里的一种特殊模型,也是一种特殊的网络流。其最大的特点在于,可以将图里的顶点分为两个集合,且集合内的点没有直接关联。
二分图判定:
如果某个图为二分图,那么它至少有两个顶点,且其所有回路的长度均为偶数(或者回路中结点个数为偶数),任何无回路的的图均是二分图。
判断二分图的方法:
判断二分图方法:用染色法,把图中的点染成黑色和白色。
首先取一个点染成白色,然后将其相邻的点染成黑色,如果发现有相邻且同色的点,那么就退出,可知这个图并非二分图。
匹配:
1. 定义: 给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
匹配点:匹配边上的两点
2. 极大匹配(Maximal Matching):是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。
3. 最大匹配(maximum matching):是所有极大匹配当中边数最大的一个匹配,设为M。选择这样的边数最大的子集称为图的最大匹配问题。
4. 完美匹配(完备匹配):一个图中所有的顶点都是匹配点的匹配,即2|M| = |V|。完美匹配一定是最大匹配,但并非每个图都存在完美匹配。
5. 最优匹配: 最优匹配又称为带权最大匹配,是指在带有权值边的二分图中,求一个匹配使得匹配边上的权值和最大。一般X和Y集合顶点个数相同,最优匹配也是一个完备匹配,即每个顶点都被匹配。如果个数不相等,可以通过补点加0边实现转化。一般使用KM算法解决该问题。(KM(Kuhn and Munkres)算法,是对匈牙利算法的一种贪心扩展。)
6. 最小覆盖
二分图的最小覆盖分为最小顶点覆盖和最小路径覆盖:
①最小顶点覆盖是指最少的顶点数使得二分图G中的每条边都至少与其中一个点相关联
注:二分图的最小顶点覆盖数=二分图的最大匹配数
②最小路径覆盖也称为最小边覆盖,是指用尽量少的不相交简单路径覆盖二分图中的所有顶点。
注:二分图的最小路径覆盖数=|V|-二分图的最大匹配数
7. 最大独立集
最大独立集是指寻找一个点集,使得其中任意两点在图中无对应边。对于一般图来说,最大独立集是一个NP完全问题,对于二分图来说最大独立集=|V|-二分图的最大匹配数。最大独立集S 与 最小覆盖集T 互补。

例题: HDU2444 The Accomodation of Students
题意: 一些学生存在认识与不认识的关系,但这种关系不传递。问能否将学生分为两组,每组中的学生互相不认识(即二分图判定)。若可以,把相互认识的同学放在一个双人间,问最多需要几个双人间(即二分图最大匹配)。
题解: 判定二分图用染色法,求最大匹配图可以用匈牙利算法,不会的可以去学习一下。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
using namespace std;
typedef long long  ll;
const int MAXN=1e4+5;
const int mod=1e9+7;
const int INF =0x3f3f3f;
int n,m;
int e[205][205];
int vis[205];//标记为染黑色或者白色
int match[205];
bool istow()//判断是否为二分图
{
    
    
    memset(vis,0,sizeof vis);
    queue<int>q;
    q.push(1);
    vis[1]=1;
    while(!q.empty())
    {
    
    
        int now=q.front();
        q.pop();
        for(int i=1;i<=n;i++)
        {
    
    
            if(e[now][i]==1)
            {
    
    
                if(vis[i]==0)//未染色,则进行染色
                {
    
    
                    if(vis[now]==1) vis[i]=2;//与now点的颜色相反
                    else vis[i]=1;
                    q.push(i);
                }
                else if(vis[i]==vis[now])
                {
    
    
                    return false;//若两个点颜色相等,则不是二分图。
                }
            }
        }
    }
    return true;
}
int finder(int i)//寻找最大二分匹配图(匈牙利算法)
{
    
    
    for(int j=1;j<=n;j++)
    {
    
    
        if(!vis[j]&&e[i][j]==1)
        {
    
    
            vis[j]=1;
            if(match[j]==0||finder(match[j]))
            {
    
    
                match[j]=i;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    
    
    while(scanf("%d%d",&n,&m)!=EOF)
    {
    
    
        memset(e,0,sizeof e);
        int a,b;
        for(int i=1;i<=m;i++)
        {
    
    
            scanf("%d%d",&a,&b);
            e[a][b]=1;
            e[b][a]=1;
        }
        if(!istow()||n==1)
        {
    
    
            printf("No\n");
            continue;
        }
        memset(match,0,sizeof match);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
    
    
            memset(vis,0,sizeof vis);
            ans+=finder(i);
        }
        printf("%d\n",ans/2);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45755679/article/details/107403097
今日推荐