華電北風吹
天津大學認知計算與應用重點實驗室
日期:2016-07-15

一、二分圖的幾個相關定義:
最大匹配:匹配邊最多。
完美匹配:所有的頂點全部是匹配點。
最佳完美匹配:邊有權重,完美匹配中匹配邊權值和最大。

二、最佳完美匹配中需要了解的幾個定義
頂標:給每個頂點賦一個數值,成為該頂點的定標。
可行頂標:如果對於所有的邊,滿足此邊兩端的兩個頂點的定標和不小於此邊權重,則稱這一組頂標為可行頂標。
相等子圖:在當前頂標下,滿足邊兩端的兩個頂點的定標和正好等於此邊權重的所有邊,所構成的子圖。

三、KM演算法(Kuhn-Munkres演算法,匈牙利演算法)
對於二分圖的一部,初始定標為當前結點所連線邊權重最大值,另一部初始定標全為0,然後對於每個節點進行匹配。若相等子圖存在可擴充套件路徑則更新匹配關係,換下一個節點;若不存在擴充套件路徑,則更新定標,使匈牙利樹增加一條邊即可(由匈牙利樹的性質可知,這條邊必是從根節點同側匹配點到另一側非匹配點,根據這個更新對應點頂標即可)。具體更新規則見模板程式碼update部分。

四、參考程式碼

#include <iostream>
#include <algorithm>
using namespace std;

#define maxn 5

int W[maxn][maxn], n;
int Lx[maxn];
int Ly[maxn];
int Left[maxn];
bool S[maxn], T[maxn];

bool Match(int i)
{
    S[i] = true;
    for (int j = 1; j <= n; j++)
    {
        if (Lx[i] + Ly[j] == W[i][j] && !T[j])
        {
            T[j] = true;
            if (!Left[j] || Match(Left[j]))
            {
                Left[j] = i;
                return true;
            }
        }
    }
    return false;
}

void Update()
{
    int a = 1 << 30;
    for (int i = 1; i <= n; i++)
    {
        if (S[i])
        {
            for (int j = 1; j <= n; j++)
            {
                if (!T[j])
                {
                    a = min(a, Lx[i] + Ly[j] - W[i][j]);
                }
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (S[i])
            Lx[i] -= a;
        if (T[i])
            Ly[i] += a;
    }
}

void KM()
{
    for (int i = 1; i <= n; i++)
    {
        Left[i] = 0;
        Lx[i] = 0;
        Ly[i] = 0;
        for (int j = 1; j <= n; j++)
        {
            Lx[i] = max(Lx[i], W[i][j]);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        while (true)
        {
            memset(S, 0, sizeof(S));
            memset(T, 0, sizeof(T));
            if (Match(i))
                break;
            else
                Update();
        }
    }
}

int main()
{
    return 0;
}

五、擴充套件問題
覆蓋集:對於每條邊,至少要有一個點要被選中。
獨立集:對於每條邊,至少要有一個點不被選中。
二分圖的最大獨立集:選擇儘量多的點,使得任意兩個節點不相鄰(即任意一條邊的兩個端點不會同時被選中)。
二分圖的最小覆蓋::選擇儘量少的點,使得每條邊至少有一個端點被選中。
並且有最小覆蓋數加最大獨立集個數等於節點個數。
棋盤中的車,指派問題,最小集合覆蓋