這篇博客介紹了匈牙利算法的操作步驟,不討論原理。
作用
解決指派問題。所謂的指派問題就比如:甲乙丙三個人去做ABC三件事情。每個人做每件事情所花的時間可能不一樣。每個人只能安排一件事情,問怎樣安排才能使三個人所工作的時間之和最小?
擴展成 n 個人 n 件事也可以,但要求是:
- 事情數和人數一樣多
- 每人只能做一件事
這樣的問題就稱作指派問題
匈牙利算法就是解決這樣的問題的。
實例
甲乙丙中第i (i=1,2,3)
個人做ABC中第j (j=1,2,3)
件事的時間爲 Aij。矩陣 A 如下
2 3 4
3 4 6
5 6 1
就是說甲做A事情要2分鐘,做B事情要3分鐘; 乙做C事情要6分鐘,以此類推。問怎樣安排才能使甲乙丙三人所用的時間最少?
下面用匈牙利算法來解。
算法目標
讓矩陣中出現 n 個滿足不同行不同列的 0。 上述問題就是要3個不同行不同列的0.
步驟概括
- 每行減去此行最小數
- 判斷是否達到算法目標,如未達到算法目標,繼續下一步。否則結束。
- 橫縱交替,從行開始。找出所有還沒有選中
0
的行(具體見步驟實例),在此行後面打鉤; 把此行中有0
的列全打鉤。在打鉤的列中,如果有零,又在有0
的行打鉤,如此交替,直到不能再打鉤。 - 在沒有打鉤的行和打鉤的列上劃線,會得到發現所有的
0
已經被劃去,如果沒有劃去,請檢查前面的步驟。此時剩下的所有元素中,找到最小值,就記爲min
吧。 - 在第4步畫線的行減去
min
(此時原來的0
變成-min
),再在畫線的列加上min
(此時矩陣中沒有了負數)。回到第 2 步。
步驟實例
對於之前的矩陣
2 3 4
3 4 6
5 6 1
- 每行減去此行最小值,由(1)變成(2),如圖:
2. 檢查發現沒有達到算法目標,因爲(2)中只有兩個不同行不同列的0
,圖中紅色的0
。沒有達到算法目標。
3. 找出沒有選中0
的行,在後面畫勾,如圖(3)。
此行的0
在第1列,在第 1 列畫勾,如圖(4),發現第 1 列有兩個 0,其中第一行的 0 還沒有畫勾,於是在第 1 行後畫勾,如圖(5)。此時沒有勾可畫了,進行下一步。
4. 在沒有打鉤的行,即第 3 行,和打鉤的列,即第 1 列,劃線,會得到發現所有的0
已經被劃去。然後找出最小值min,此處min = 1
。如圖(6)
5. 在第4步畫線的行減去min
,即在第1、2行減去 1,結果如圖(7)。再在畫線的列加上min
,即在第 1 列加上 1,結果如圖(8)。
6. 判斷髮現(8)滿足算法目標,當然也有圖(9)滿足算法目標。
最後一公里
如圖(8),第1、2、3行的 0 分別在相應行的第 1 、2、3個,所以第 1 個人做第 1 件事,第 2 個人做第 2 件事,第 3 個人做第 3 件事。
圖(9)對應的是第 1 個人做第 2 件事,第 2 個人做第 1 件事,第 3 個人做第 3 件事。
帶入圖(1)計算可以知圖(8)和圖(9)所用的時間相同,都是(2+4+1 = 7)或 (3+3+1 = 7)分鐘。
我們把圖(8)和圖(9)的結果分別寫成
1 2 3
1 2 3
1 2 3
2 1 3
總結
要想最快掌握匈牙利算法,就在看完我這篇博客後自己默寫一篇。我就是這樣做的,現在感覺很好。教別人是一種很好的學習方式,沒人教就自己寫寫博客分享嘍!你也可以自己算一個例子試試,其實我已經幫你想好了:對於下面的矩陣,求最少工作量。(希望在你的手機或電腦屏幕上也能看到的矩陣排列得整齊,美感總是很重要的)
5 7 11 5 7
4 8 3 2 2
5 4 6 10 7
10 12 11 10 10
3 7 8 4 5
我得出的結果如下,也未必對,我沒有檢查:
1 2 3 4 5
4 5 2 3 1
文中若有不足之處,歡迎指正。