1. 程式人生 > 實用技巧 >匈牙利演算法-二分圖的最大匹配

匈牙利演算法-二分圖的最大匹配

匈牙利(Hungarian)演算法-二分圖的最大匹配問題


首先是一個小的講解視訊

上述視訊涉及到的一個打卡題目杭電OJ-2063-過山車

我的程式碼如下:(下面的程式碼同視訊裡的稍有不同,或者說是男女正好相反吧)

#include<bits/stdc++.h>
using namespace std;

const int maxn = 505;
int dict[maxn][maxn];
int vis[maxn];
int nxt[maxn];//某個男生有沒有女生 
int k,m,n;//m女生,n男生 


bool match(int x)
{
	for(int i=1;i<=n;i++)//遍歷每個男生 
	{
		if(dict[x][i] && !vis[i])//如果x女生對男生有意向且該男生還沒有被訪問過
		{
			vis[i]=1;//該男生在該女生的匹配階段已經被訪問過
			if(nxt[i]==0 || match(nxt[i]))//如果男生沒有被配對或者該男生配對的女生可以變換
			{
				nxt[i]=x;
				return true;
			}
		}
	}
	return false;
}

int solve()
{
	int sum = 0;
	for(int i = 1;i<=m;i++)//遍歷每個女生 
	{
		memset(vis,0,sizeof(vis));
		if(match(i))sum++;
	}
	return sum;
}

int main()
{
	while(cin>>k && k)
	{
		//讀入資料
		memset(dict,0,sizeof(dict));
		cin>>m>>n;
		for(int i=0;i<k;i++)
		{
			int g,b;
			cin>>g>>b;
			dict[g][b]=1;
		}
		//初始化
		memset(nxt,0,sizeof(nxt)); 
		//解決問題
		cout<<solve()<<endl; 
	}
	return 0;
}

其實,上面那個視訊並沒有過多的涉及到匈牙利演算法的內容,
也沒有很好的講明白遞迴演算法的實現。
不過,這至少讓你對匈牙利演算法的大致思想有所瞭解。
下面,將會詳細說明匈牙利演算法及其前置概念。


接下來是一個CSDN的博文。
這個部落格完全沒有程式碼,但是它十分清晰的講解了匈牙利演算法演算法精髓。

部落格連結

注意演算法關鍵詞:二部圖(二分圖)、增廣路、遞迴、後來者居上


結合上面的解釋以及打卡題目的程式碼,我們可以基本得到一個模板:

const int MAXN = 500;
int M, N;            //M, N分別表示左、右側集合的元素數量
int Map[MAXM][MAXN]; //鄰接矩陣存圖
int p[MAXN];         //記錄當前右側元素所對應的左側元素
bool vis[MAXN];      //記錄右側元素是否已被訪問過

bool match(int i)
{
    for (int j = 1; j <= N; ++j)
        if (Map[i][j] && !vis[j]) //有邊且未訪問
        {
            vis[j] = true;                 //記錄狀態為訪問過
            if (p[j] == 0 || match(p[j])) //如果暫無匹配,或者原來匹配的左側元素可以找到新的匹配
            {
                p[j] = i;    //當前左側元素成為當前右側元素的新匹配
                return true; //返回匹配成功
            }
        }
    return false; //迴圈結束,仍未找到匹配,返回匹配失敗
}

int Hungarian()
{
    int cnt = 0;
    for (int i = 1; i <= M; ++i)
    {
        memset(vis, 0, sizeof(vis)); //重置vis陣列
        if (match(i))
            cnt++;
    }
    return cnt;
}

OK