zoukankan      html  css  js  c++  java
  • 图论2——二分图与匈牙利算法

    本文作者frankchenfu,blogs网址http://www.cnblogs.com/frankchenfu/,转载请保留此文字。

    一般情况下,我们用的都是简单图。带权图,无向图;还有各种算法,像Floyd,SPFA,Dijkstra……

    但是,在我们需要进行一些匹配问题的时候,我们就不能够只是用简单图了,不然最终可能会收获TLE(超时)。

    这个时候,我们就要让二分图出场了!

    1、二分图的应用

    我们举一个最简单的例子。有N名男运动员和M名女运动员要组成尽可能的多的混双配对,其中有一些不能够配对,请问如何处理?

    这时候,大家就可能比较头疼——没有什么思路。各种数据结构似乎也都无能为力,组合数论看起来可以,实际上也算不出来,更不会有人想到这是图论。

    然而这就是一道二分图模板题。

    【题目大意】

    有N名男运动员和M名女运动员要组成尽可能的多的混双配对,其中有一些不能够配对,请问如何处理?

    【输入格式】

    第一行 输入三个整数,N,M,K,,表示男运动员的个数,女运动员的个数,以及可匹配对数。

    以下K行,每行两个整数a,b,表示男运动员a,b可以配对比赛。

    【输出格式】

    只有一个整数,为最多的混双配对。

    【输入样例】

    5 4 14

    1 1

    1 2

    2 3

    3 2

    4 2

    4 3

    4 4

    5 4

    5 2

    5 3

    3 3

    2 4

    1 3

    2 1

    【输出样例】

    4

    【算法分析】

    我们之前已经分析过它是一道图论题,但是怎么建图呢?

    如果我们把每一个运动员看做图的顶点V,将每一对可配对的连接,则上面的样例可以表示为下图(无向图)。

    那么你会做了吗?

    其实上面这张图就是一张二分图。二分图的定义大致如下。

    图G=[V,E]是一个无向图,顶点集合V分为X和Y两部分,G中的每一条边一定一个端点在X,一个端点在Y。

    所以,二分图也可以记为G=[X,Y,E]。

    我们也知道,有一种东西叫做完全二叉树,那么有没有完全二分图呢?

    当然有。当X中的任意结点都与Y中的地所有节点连接时,它就是一个完全二分图(因为是无向图,所以亦可为Y中的节点与X中所有节点连接)。

    【定理】

    当且仅当无向图G的每一个回路长度均为偶数时,该图才是一个二分图。(包括无回路的情况)

    题目中的求尽可能多的混双配对,其实也就是求二分图的最大匹配。

    2、二分图的最大匹配

    要解决二分图的最大匹配问题,我们有几种算法,例如网络流。但是,今天我要讲的,是Edmonds在1965年提出的匈牙利算法(Hungary Algorithm)。

    首先,我们来了解一些名词。在这里,我们暂时设M为一张二分图中可能出现的最大匹配方案。

    交错轨

    设P是二分图中的一条路径,如果该路径任意两条相邻边一条在M内(是最大方案的一部分),另一条不在M内(不是最大方案的一部分),那么它就是一条交错轨。

    特别的,如果该路径中只有一条边,那么他一定是一条 交错轨,不论在M内外。

    可增广轨

    我们再定义一个点“是否有连接着最大匹配方案里的边”为这个点是否被“盖住”。如果交错轨的两个定点都是没有被“盖住”的,那么他就是一个可增广轨。

    为什么要寻找可增广轨呢?因为,如果你在寻找最大匹配方案时能够找到一个可增广轨的话,那么最大匹配方案就可以增加到当前方案匹配数+1。

    讲了这么多,现在开始讲一讲匈牙利算法。

    他其实就是最开始把最大匹配方案M置为空集,然后反复寻找增广路径,知道没有为止,就这么简单。

    增广路径的找法,就是DFS或BFS。在针对稠密图时建议DFS,反之则为BFS。

    下面,给出DFS的Cpp参考代码。

    #include<cstdio>
    #include<cstring>
    const int MAX=1001;
    int n,m,k;
    int link[MAX];
    bool vis[MAX];
    bool map[MAX][MAX];
    bool dfs(int a)
    {
        for(int i=1;i<=m;i++)
            if(map[a][i]==1&&!vis[i])
            {
                vis[i]=1;
                if(!link[i]||dfs(link[i]))
                {
                    link[i]=a;
                    return 1;
                }
            }
        return 0;
    }
    int main()
    {
        int a,b,ans=0;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&a,&b);
            map[a][b]=1;
        }
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i))
                ans++;
        }
        printf("%d
    ",ans);
        return 0;
    }

    关于BFS,这里同样给出示范性的Cpp代码。

    #include<cstdio>
    #include<cstring>
    const int MAX=1001;
    
    struct link
    {
        int data;
        link *nxt;
        link(int=0);
    };
    link::link(int n)//类继承 
    {
        data=n;
        nxt=NULL;
    }
    int n,m,k,ans=0;
    int res[MAX];
    bool state[MAX];
    link *head[MAX],*lst[MAX];
    
    bool bfs(const int n)
    {
        link* t=head[n];
        while(t!=NULL)
        {
            if(!state[t->data])
            {
                state[t->data]=1;
                if(!res[t->data]||bfs(res[t->data]))
                {
                    res[t->data]=n;
                    return 1;
                }
            }
            t=t->nxt;
        }
        return 0;
    }
    int main()
    {
        int a,b;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<k;i++)
        {
            scanf("%d%d",&a,&b);
            if(lst[a]==NULL)
                lst[a]=head[a]=new link(b);
            else
                lst[a]=lst[a]->nxt=new link(b);
        }
        for(int i=1;i<=n;i++)
        {
            memset(state,0,sizeof(state));
            if(bfs(i))
                ans++;
        }
        printf("%d
    ",ans);
        return 0;
    }

    本篇博客到这里就结束了,希望大家能满意,然后点个赞,谢谢!

  • 相关阅读:
    【HTTP】一、HTTP协议简介及其工作流程
    【总结】计算机网络常见问题
    【LeetCode】714、买卖股票的最佳时机含手续费
    【LeetCode】309、最佳买卖股票时机含冷冻期
    【LeetCode】188、买卖股票的最佳时机 IV
    【LeetCode】123、买卖股票的最佳时机 III
    【LeetCode】122、买卖股票的最佳时机 II
    【LeetCode】121、买卖股票的最佳时机
    windows搭建测试环境
    css 和常用快捷键
  • 原文地址:https://www.cnblogs.com/frankchenfu/p/6713286.html
Copyright © 2011-2022 走看看