二分圖匹配入門

之前大一的時候有學姐講過二分圖匹配的匈牙利(Hungrain)算法,當時沒理解。最近想補補圖論,學習一下二分圖匹配的匈牙利算法,其實挺簡單的。

先弄清二分圖匹配時重要的幾個概念:

(1)交替路:從一個未匹配的頂點出發,依次經過未匹配邊,匹配邊...,這樣由匹配邊,非匹配邊交替形成的路稱爲交替路。一定先理解這個概念,才能理解增廣路的概念。

(2)增廣路:從一個未匹配的頂點出發,沿交替路走,到達第一個未匹配頂點時到達終點,這個過程形成的路稱爲增廣路。


增加匹配的關鍵在於在整個圖中尋找增廣路,如果找不到增廣路,則已經找到最大匹配(Berge 定理)。否則,我們可以將增廣路中所經過的邊進行修改,若其原來是匹配邊,則我們將其修改爲未匹配邊。若其原來是未匹配邊,則將其變爲匹配邊。這樣可以增加一對匹配。爲什麼呢?因爲增廣路上一定是匹配邊比未匹配邊少一條,可以根據定義想一想。有了這個性質,那麼我們就只需要找增廣路就行了。再根據Berge定理,就找到了最大匹配。看兩幅圖來感受一下尋找增廣路增加匹配的例子:


圖1 圖2

我們選擇從左邊的頂點集出發,第一個未匹配的頂點是 4,於是我們從4開始走交替路, 4->7->1->6, 到達6時沒有路可以走了,但此時沒有到達未匹配頂點,因此,從4出發沒有找到增廣路。所以我們從5出發, 5->9->2->10,這個時候我們找到了一條增廣路,把5-9, 2-10由未匹配邊變爲匹配邊,把2 - 9由匹配邊變爲未匹配邊,看看這個時候是不是多了一條匹配?由於左邊頂點集已經沒有未匹配的頂點能擴展增廣路,故此時匹配已經達到最大。


hdu 2063 是一道入門級的二分圖匹配。實現算法中圖的存儲結構選擇了鄰接表。

 

#include<stdio.h>
#include<string.h>
#include<vector>

using namespace std;

const int MAX = 2048;

vector<int> G[MAX];
typedef vector<int>::iterator iterator_vi;
int matched[MAX];
int vis[MAX];
int n, m, k;

bool dfs(int u)
{
    for(iterator_vi i = G[u].begin(); i != G[u].end(); i++)
    {
        int v = *i;
        if(!vis[v])
        {
            vis[v] = 1;
            if(matched[v] == -1 || dfs(matched[v]))
            {
             //   printf("%d %d\n", u, v);
                matched[u] = v;
                matched[v] = u;
                return true;
            }
        }
    }
    return false;
}

int hungrain()
{
    int ret = 0;
    memset(matched, -1, sizeof(matched));
    for(int i = 1; i <= m; i++)
    {
        if(matched[i] == -1)
        {
            memset(vis, 0, sizeof(vis));
            if(dfs(i))
                ret++;
        }
    }
    return ret;
}

int main()
{
    freopen("in.txt", "r", stdin);
    while(~scanf("%d", &k))
    {
        if(k == 0) break;
        scanf("%d%d", &m, &n);

        for(int i = 1; i <= m; i++)
            G[i].clear();
        for(int i = 0; i < k; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            b += m;
            G[a].push_back(b);
        }
        printf("%d\n", hungrain());
    }
    return 0;

}



發佈了49 篇原創文章 · 獲贊 9 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章