「知识学习」二分图的最大匹配、完美匹配和匈牙利算法(HDU-2063)

定义

如果一个图\((E,V)\)的顶点集\(E\)能够被能够被分成两个不相交的集合\(X,Y\),且每一条边都恰连接\(X,Y\)中的各一个顶点,那么这个图就是一个二分图
容易得知,它就是不含有奇数环的图(这个等价定义有时候很重要)。
一个匹配是一个边的集合,其中任意两条边都没有公共顶点。顾名思义可以得到一个图的最大匹配的定义。特别地,如果一个图的某个匹配中,所有顶点都是匹配点,那么它是一个完美匹配
由完美匹配和最大匹配这两个定义我们可以得到两类问题:

  1. 有没有可能使得所有顶点都被匹配?
  2. 一个图中最多有多少个顶点参与了匹配?

求解最大匹配:匈牙利算法

对于一个正在求匹配的图,我们把依次经过非匹配边、匹配边、非匹配边、……形成的路径叫交替路;而如果一个未匹配点走交替路到了另外一个未匹配点,那么这条交替路成为增广路
仔细思考一下,就会发现增广路的一个特点:非匹配边比匹配边多一条。这有什么意义呢?当我们把增广路中匹配边、非匹配边的性质交换后,匹配的性质不变,但是匹配边多了一条——我们改进了匹配。
因此,我们可以通过不停的找增广路来增加匹配中的匹配边和匹配点。然后,根据增广路定理,一个图找不到增广路时,就是它达到最大匹配的时候。
下面简单的说一下匈牙利算法:

  1. 从二分节点后的左边第1个顶点开始,挑选未匹配点进行搜索,寻找增广路。 a. 如果经过一个未匹配点,说明寻找成功。更新路径信息,匹配边数+1,停止搜索。 b. 如果一直没有找到增广路,则不再从这个点开始搜索。事实上,此时搜索后会形成一棵匈牙利树。我们可以永久性地把它从图中删去,而不影响结果。
  2. 由于找到增广路之后需要沿着路径更新匹配,所以我们需要一个结构来记录路径上的点。DFS 版本通过函数调用隐式地使用一个栈,而 BFS 版本使用pre数组。
    上面提到了匈牙利树。那么这个是什么?匈牙利树他是这样的性质,从根节点到叶节点的路径均是交替路,且匈牙利树的叶节点都是匹配点

例题:HDU-2063 过山车

经典板子题。

#include <bits/stdc++.h>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (repType i = (a); i <= (b); ++i)
#define per(i, a, b) for (repType i = (a); i >= (b); --i)
#define QUICKIO                  \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0);
using namespace std;
typedef long long ll;
typedef int repType;
const int MAXN=505;
int k,m,n;
bool mat[MAXN][MAXN],used[MAXN];
int linker[MAXN];

int dfs(int boy)
{
    rep(g,1,n) // girl
    {
        if(mat[boy][g] && !used[g])
        {
            used[g]=true;
            if(linker[g]==-1 || dfs(linker[g]))
            {
                linker[g]=boy;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int ans=0;
    memset(linker,-1,sizeof(linker));
    rep(b,1,m) // boy
    {
        ZERO(used);
        if(dfs(b)) ans++;
    }
    return ans;
}

int main()
{ 
    while(cin>>k)
    {
        if(!k) break;
        cin>>m>>n;
        ZERO(mat);
        rep(i,1,k)
        {
            int a,b; cin>>a>>b;
            mat[a][b]=true;
        }
        cout<<hungary()<<endl;
    }
    return 0;
}

其他的题型

简单改一下:HYSBZ - 1191 超级英雄Hero

最小路径覆盖

二分图最大独立集

参考网址与资源

https://www.renfei.org/blog/bipartite-matching.html
https://www.cnblogs.com/YiXiaoZhou/p/5875040.html
https://www.cnblogs.com/kuangbin/archive/2012/08/26/2657446.html

猜你喜欢

转载自www.cnblogs.com/samhx/p/Bipartite-Graph-Matching.html