1. 程式人生 > >匈牙利演算法—介紹與基本用途

匈牙利演算法—介紹與基本用途

匈牙利演算法應用於二分圖(即可以分為兩大部分,且個部分內不連線的圖)匹配的問題,它的時間複雜度為O(nm)。它的基本原理是增廣路

它的用途主要有三:1、單純二分圖匹配;2、最小點覆蓋;3、最大獨立集。下面,我將一一介紹。

一、單純二分圖匹配

例題1:

有n只公牛和m只母牛,然後每隻公牛都可以和幾隻的母牛配對。在每隻公牛隻能配對一隻母牛的情況下,求能為牛們配對最多多少對?

思路:公牛是二分圖的一個集合,母牛也是。接著公牛逐一詢問母牛,會出現兩種情況。1、如果母牛未被匹配,公牛匹配它;2、如果母牛已被匹配,詢問母牛的原配公牛能否換另一頭母牛匹配。若行,則該公牛可以獲得此母牛;反之,該公牛無法得到該母牛。如果該失配公牛問遍了所有母牛,仍然不能找到合適的配偶,則該公牛匹配失敗(ans不能+1)。

程式碼:

#include<cstdio>
#include<cstring>
using namespace std;

int n,m,ans;
int match[210];//母牛i的配偶是公牛match[i]
bool chw[210];//在此趟詢問中,母牛i是否被詢問過
bool mp[210][210];//公牛i與母牛j是否有關係

bool find_ans(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(mp[x][i]==true&&chw[i]==true)
		{
			chw[i]=false;
			if(match[i]==0||find_ans(match[i])==true)
			//母牛沒有配偶||匹配該母牛的公牛能否換一頭母牛匹配 
			{
				match[i]=x;
				return true;
			}
		}
	}
	return false;
}

int main()
{
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		memset(mp,false,sizeof(mp));
		for(int i=1;i<=n;i++)
		{
			int k,x;
			scanf("%d",&k);
			for(int j=1;j<=k;j++)
			{
				scanf("%d",&x);
				mp[i][x]=true;
			}
		}
		ans=0;
		memset(match,0,sizeof(match));
		for(int i=1;i<=n;i++)
		{
			memset(chw,true,sizeof(chw));
			if(find_ans(i)==true) ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

解題關鍵:構造二分匹配圖,找到可連線的線的條件(mp[ ][ ]==true?)。

二、最小點覆蓋

一般考場上的題目極少是純匈牙利演算法,多數會蓋上“最小的覆蓋”的薄紗。

對於求最小點覆蓋的題,我們要運用結論:二分圖中 最小點覆蓋數 = 最大匹配數 ,因此求最小點覆蓋的覆蓋的題轉化為了求最大匹配數的題。

例題2:(poj 1325)

有兩部機器A和B。A機器有n種工作模式0,1,2,3…… n-1 總共n種;B機器有m中工作模式0,1,2,3…… m-1 總共m種。有k個任務,每個任務可以在A機器的某個模式或者B機器的某個模式中完成。A和B機器開始時都預設在0模式,要選擇其他模式就要重啟一次。求完成k個任務至少需要重啟多少次機器。

思路:構圖:X集合表示A機器的模式編號,Y集合表示B機器的模式編號,如果兩個模式能完成的任務相同,則給它們連邊,也就是說,任務用來表示

例題3:(poj 3692)

G個女孩,B個男孩,女孩之間相互認識,男孩之間相互認識,某些男孩同女孩之間相互認識,求最大的相互認識的集合的人數。

思路:該題棘手於“女孩之間相互認識,男孩之間相互認識”,因為如果就此構圖,會出現G集合和B集合內相互連邊,不符合二分圖的定義,因此,我們得另闢新路來構圖。構圖:把沒有關係的兩點連線,反向建圖(即建補圖)。

程式碼:

#include<cstdio>
#include<cstring>
using namespace std;

int g,b,m,ans;
int match[210];
bool mp[210][210];//mp[i][j]==true時,表示i女生與j男生互不認識
bool chw[210];

bool find_ans(int x)
{
	for(int i=1;i<=b;i++)
		if(mp[x][i]==true&&chw[i]==true)
		{
			chw[i]=false;
			if(match[i]==0||find_ans(match[i])==true)
			{
				match[i]=x;
				return true;
			}
		}
	return false;
}

int main()
{
	int Case=0;
	while(scanf("%d%d%d",&g,&b,&m)&&g!=0&&b!=0&&m!=0)
	{
		Case++;
		memset(mp,true,sizeof(mp));//互不認識 
		for(int i=1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			mp[x][y]=false;//他倆認識 
		}
		
		ans=0;
		memset(match,0,sizeof(match));
		for(int i=1;i<=g;i++)
		{
			memset(chw,true,sizeof(chw));
			if(find_ans(i)==true) ans++;//統計不認識的人數 
		}
		printf("Case %d: %d\n",Case,g+b-ans);//輸出 總人數-不認識人數 
	}
	return 0;
}

三、最大獨立集

有關最大獨立集的題,我們如果利用結論:最大獨立集 點數= 總點數 - 最小點覆蓋 = 總點數 - 最大匹配數,就可以用匈牙利演算法輕鬆求解。若要求獨立集的數量,可以通過強聯通來求。

如 例題3,它在求“最大的相互認識的集合的人數”其實本質就是求最大獨立集點數,所以它的答案(最大獨立集點數)= 總人數(總點數)- 不認識人數(最大匹配數)。

例題4:(poj 1466)

一些女生與男生有浪漫關係,求一個集合中的最大人數,滿足這個集合中兩兩的人不能配對。其中男生與男生間和女神與女生間本就有有浪漫關係。

思路:構圖:把X集合的人複製到Y集合,如果兩個人有浪漫關係,則給他們連邊,最後通過 最大獨立集點數=總點數-最大匹配數 得到答案,但需注意,此圖中的點相當於兩個X集合,所以得到的最大匹配數要除以2。

文章最後,介紹關於匈牙利演算法的一種簡單的優化方法:建鄰接表。以節省不必要的重複判斷,這樣可以大大減少時間,但空間可能會有改變,碼量要大些。

相關推薦

匈牙利演算法介紹基本用途

匈牙利演算法應用於二分圖(即可以分為兩大部分,且個部分內不連線的圖)匹配的問題,它的時間複雜度為O(nm)。它的基本原理是增廣路。它的用途主要有三:1、單純二分圖匹配;2、最小點覆蓋;3、最大獨立集。下

1.Angular框架-angular介紹基本使用,MVC模式介紹

就會 web javascrip 點擊 技術分享 fig page 格式 存儲 1.1. AngularJS概述 1.1.1. 介紹 簡稱:ng Angular是一個MVC框架 AngularJS 誕生於2009年,由 Misko Hevery 等人創建,後為Goog

Haproxy介紹基本應用初探

haproxy介 haproxy負載應用 haproxy配置 haproxy管理腳本 HAProxy是什麽 TCP代理軟件:L4(偽四層)http反向代理軟件:七層應用代理支持SSL連接:支持客戶端到到Haproxy,Haproxy到後面服務器,以及全程SSL的支持負載均衡器,支持會話粘性;H

不平衡資料分類演算法介紹比較

介紹 在資料探勘中,經常會存在不平衡資料的分類問題,比如在異常監控預測中,由於異常就大多數情況下都不會出現,因此想要達到良好的識別效果普通的分類演算法還遠遠不夠,這裡介紹幾種處理不平衡資料的常用方法及對比。 符號表示 記多數類的樣本集合為L,少數類的樣本集合為S。

Linux介紹基本必知命令

1.系統結構介紹 linux的由來 Linux作業系統是基於UNIX作業系統的, 其核心主要是由C程式編寫。Linux是自由和開放的,任何組織和個人只要遵循GNU通用公共許可證協議都可以自由免費地使用Linux的所有底層原始碼,並可以自由地修改和分發。 2.linux的目錄結構 Linux和Windo

cassandra簡單介紹基本操作

一、使用場景:   是一款分散式的結構化資料儲存方案(NoSql資料庫),儲存結構比Key-Value資料庫(像Redis)更豐富,但是比Document資料庫(如Mongodb)支援度有限;適合做資料分析或資料倉庫這類需要迅速查詢且資料量大的應用   相關概念:   &n

django之ORM介紹基本用法(一)

  一、ORM介紹 1.什麼是ORM ORM 全拼Object-Relation Mapping. 中文意為 物件-關係對映. 在MVC/MVT設計模式中的Model模組中都包括ORM 2.ORM優勢 (1)只需要面

jQuery介紹基本語法,選擇器

1.jQuery介紹 1.1JS類庫 JavaScript 庫封裝了很多預定義的物件和實用函式。能幫助使用者建立有高難度互動客戶端頁面, 並且相容各大瀏覽器。 1.2當前流行的 JavaScript 庫有: jQuery ,最流行 EXT_JS,2.0

深度學習常見演算法介紹比較

很多人都有誤解,以為深度學習比機器學習先進。其實深度學習是機器學習的一個分支。可以理解為具有多層結構的模型。具體的話,深度學習是機器學習中的具有深層結構的

KVM簡單介紹基本使用

簡介 KVM(Kernel-basedVirtual Machine,基於核心的虛擬機器)是適用於包含虛擬化擴充套件(Intel VT或AMD-V)的x86硬體上的Linux的完全虛擬化解決方案。它由可載入的核心模組kvm.ko組成,它提供核心虛擬化基礎架構和處

Druid 介紹基本概念

1.概述     隨著網際網路快速發展,資料量增長快,達到TB、PB,以交通車流量為例,如湖南省每月的車輛流量至少達到4億,這個資料量遠不止如此。資料量如此大,如何滿足後期分析,傳統面向OLTP型資料庫(ORACLE、MYSQL等)無法要求,漸漸開始轉向OLAP

Quartz2教程(一)——quatz的介紹基本概念

很久沒有記錄一下新的東西了,最近看了一下java平臺上的quartz框架,並計劃把它使用在目前的專案中,去解決一些問題,如定時計算使用者的收益,定時提醒使用者預訂的資源需要被使用等等。 一、quart

Prettier介紹基本用法

Prettier Prettier的中文意思是“漂亮的、機靈的”,也是一個流行的程式碼格式化工具的名稱,它能夠解析程式碼,使用你自己設定的規則來重新打印出格式規範的程式碼。 Prettier具有以下幾個有優點: 1. 可配置化 2. 支援多種語言

隱馬爾可夫模型學習筆記(一):前後向演算法介紹推導

學習隱馬爾可夫模型(HMM),主要就是學習三個問題:概率計算問題,學習問題和預測問題。概率計算問題主要是講前向演算法和後向演算法,這兩個演算法可以說是隱馬爾可夫的重中之重,接下來會依次介紹以下內容。 隱馬爾可夫模型介紹 模型的假設 直接計演算法,前向演算法,後向演

iOS開發——圖形程式設計OC篇&(一)CALayer介紹基本使用

在iOS中,你能看得見摸得著的東西基本上都是UIView,比如一個按鈕、一個文字標籤、一個文字輸入框、一個圖示等等,這些都是UIView。 其實UIView之所以能顯示在螢幕上,完全是因為它內部的一個圖層,在建立UIView物件時,UIView內部會自動建立一個圖層(即CALayer物件),通過UIVi

服務編排--Conductor 文件翻譯 (介紹基本概念)

本文是對 Conductor 文件的簡單翻譯,建議你認真閱讀,如果閱讀後你仍然不知道如何使用,可以繼續關注本部落格,我會在後續的部落格中更新 Conductor 實戰 介紹 Conductor是一個微服務的編排引擎 Conductor 優

AVL樹演算法介紹總結

在電腦科學中,AVL樹是最先發明的自平衡二叉查詢樹。在AVL樹中任何節點的兩個子樹的高度最大差別為一,所以它也被稱為高度平衡樹。查詢、插入和刪除在平均和最壞情況下都是O(log n)。增加和刪除可能需要通過一次或多次樹旋轉來重新平衡這個樹。AVL樹得名於它的發明者 G.M. Adelson-Velsky 和

Kruskal演算法介紹實現

最小生成樹(MinimumSpanning Tree,MST)或者稱為最小代價生成樹:對無向連通圖的生成樹,各邊的全值總和稱為生成樹的權,權最小的生成樹稱為最小生成樹。 構造最小生成樹的準則有三條: (1)必須只使用該網路中的邊來構造最小生成樹; (2)必須使用且僅使用n

幾種排序演算法介紹效能分析

本文以對整形陣列升序排序為例,列舉了排序的幾種演算法及相應的Java實現,並在本文最後給出這幾種演算法的效能分析圖表。 1、插入排序  基本思路:在每次迴圈中把一個元素插入到已經排序的部分序列裡的合適位置,使得到的序列仍然是有序的。 實現: void sort(int a

Huffman樹Huffman編碼—介紹基本應用

今天來談談huffman樹吧。 先介紹一下樹的路徑長度(path length of a tree,PL),和樹的帶權路徑長度(Weighted Path Length of Tree,WPL)。我們定義每個節點到樹根的距離為l[i]。樹的路徑長度(PL):所有節點到根的距