二分图的判定(染色法)和二分图最大匹配(匈牙利)算法及模板

定义

  二分图也称二部图,是图论里的一种特殊模型,也是一种特殊的网络流。其最大的特点在于,可以将图里的顶点分为两个集合,且集合内的点没有直接关联,如下图所示。

如果某个图为二分图,那么它至少有两个顶点,且其所有回路的长度均为偶数,任何无回路的的图均是二分图。

 1.染色法判断二分图

 染色法是对每一个点深搜,与这个点连接的点颜色与此点相反,如果存在环且是偶数环或则不存在环,则满足该条件,如果存在奇数环则不满足(推出矛盾)

#include<iostream>
#include<cstring>
using namespace std;
int h[100010],e[200010],ne[200010],idx;
int color[100010];int n,m;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int u,int c)
{
    color[u]=c;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!color[j])//未被染色的话
        {
            if(!dfs(j,3-c))return false;
        }
        else if(color[j]==c)//如果领结的点与本点颜色一样,则存在奇数环,不是二分图
        return false;
    }
    return true;
}
int main()
{
    memset(h,-1,sizeof h);cin>>n>>m;
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    int f=1;
    for(int i=1;i<=n;i++)
    {
        if(!color[i])//未被染色的话
        {
            if(!dfs(i,1))
            {
                f=0;
                break;
            }
        }
    }
    if(f)printf("Yes\n");
    else
    printf("No\n");
    return 0;
}

2.匈牙利算法求二分图的最大匹配

首先介绍两个概念:

二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。

从左边的二分图一一枚举匹配右边(所以存从左边到右边的有向边就行),对于左边每一个点所连接的右边部分来说,

如果在这次循环时未被枚举,且未匹配左边的点或则匹配的左边的可以连接其他右边部分的点(递归实现)则该点可以匹配此时右边的点

#include<iostream>
#include<cstring>
using namespace std;
int n1,n2,m;
int h[510],e[100010],ne[100010],idx;
int match[510];//存与n2匹配的n1
int vis[510];//每一个循环时判断n2是否已经有了匹配;
void add(int a,int b)
{
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
bool find(int x)
{
    for(int i=h[x];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!vis[j])//此时n2未被选择
        {
            vis[j]=1;
            if(match[j]==0||find(match[j]))//如果此时n2未被n1选择,或则与n2选择的n1有其他的选择
            {
                match[j]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    cin>>n1>>n2>>m;
    memset(h,-1,sizeof h);
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    int res=0;
    for(int i=1;i<=n1;i++)
    {
        memset(vis,0,sizeof(vis));
        if(find(i))res++;
    }
    cout<<res<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/flyljz/p/11766389.html