zoukankan      html  css  js  c++  java
  • 二分图的判定(染色法)和二分图最大匹配(匈牙利)算法及模板

    定义

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

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

     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
    ");
        else
        printf("No
    ");
        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;
    }
  • 相关阅读:
    Linux多网卡的时候执行机器Ip
    Base64加密算法
    MD5中Java和Js配套实现
    Maven依赖war开发,找不到war里头的class解决方案
    Java文件上传下载
    ①SpringBoot入门教学篇
    Java开发过程中乱码问题理解
    git切换到新的远程地址
    使用tablayout和recyclerview的时候,报重复添加Fragment错误
    项目组件化,找不到控件, or 控件为null
  • 原文地址:https://www.cnblogs.com/flyljz/p/11766389.html
Copyright © 2011-2022 走看看