• 二分图匹配之匈牙利算法


    二分图的基本概念:

    二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

    比如:

    我们一般把图的两部分称为X部和Y部,一个图的所有点如果能被两个独立的点集,那就认为这个图是二分图

    二分图的判断一般通过染色的方法来进行判段,可以写成dfs或则bfs的写法

    bool dfs(int v,int c)
    {
        color[v]=c;
        for(int i=0;i<n;i++)
        {
            if(edge[v][i]==1)
            {
                if(color[i]==c) return false;
                if(color[i]==0&&!dfs(i,-c)) return false;
            }
        }
        return true;
    }
    void solve()
    {
        int flag=0;
        for(int i=0;i<n;i++)
        {
            if(color[i]==0)
            {
                if(!dfs(i,1))
                {
                    cout<<"no"<<endl;
                    flag=1;
                    break;
                }
            }
         } 
         if(!flag) cout<<"yes"<<endl;
    } 

    bfs写法

    bool bfs(int s)
    {
        color[s] = 1;
        queue<int> que;
        que.push(s);
        while(!que.empty())
        {
            int from = que.front();
            que.pop();
            for(int i = 1; i <= V; i++)
            {
                // 如果相邻的点没有上色就给这个点上色
                if(G[from][i] && color[i] == 0)
                {
                    que.push(i);
                    color[i] = -color[from];
                }
                // 如果相邻的颜色相同则返回false
                if(G[from][i] && color[i] == color[from])
                    return false;
            }
        }
        // 如果所有的点都被染过色,且相邻的点颜色都不一样,返回true
        return true;
    }

    接下来就是介绍匹配:

    一个匹配是一个边的集合,任何匹配的边之间没有公共顶点。

    最大匹配:一个图的所有匹配中,边数最多的匹配称为最大匹配。如果所有定点都是匹配顶点,则称这个匹配为完美匹配。

    我们一般通过匈牙利算法来求一个二分图的最大匹配,其算法的核心是求增广路径。

    交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路。*

    增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路(agumenting path)。

    我们每次找到一个增广路,所得到的匹配的边数都会增加一条,因此我们可以通过求所有点的增广路径来求最大匹配的边数

    匈牙利算法的模板如下:

    bool dfs(int x)
    {
        for(int i=1;i<=p;i++)
        {
            if(!used[i]&&map[x][i]==1)
            {
                used[i]=1;
                if(!link[i]||dfs(link[i]))
                {
                  link[i]=x;
                  return true;
                }
            }
        }
        return false;
    }
    void xyl()
    {
        for(int i=1;i<=n;i++)
        {
            memset(used,0,sizeof(used));
            if(dfs(i)) counts++;
        }
    }

    PS.练习题:hdu 1045,hdu 2444,hdu 1083

    此外还有二分图的最小顶点覆盖,最大独立集,最大团等知识,求的方法和匈牙利算法的差不多可以参考如下博客

    https://www.cnblogs.com/jianglangcaijin/p/6035945.html

    剩下的带权二分图过几天在补充

  • 相关阅读:
    Java 常提到的自然序(Natural Ordering)
    设计模式(三)行为模式
    设计模式(二)结构模式
    设计模式(一)建造者模式
    设计模式的概念以及面向对象设计原则
    Java源码 HashMap<K,V>
    mybatis注解使用
    spring整合mybatis
    数据库中的表批量映射为对象
    返回用户提交的图像工具类
  • 原文地址:https://www.cnblogs.com/tombraider-shadow/p/10945775.html
Copyright © 2020-2023  润新知