這篇文章將會對穩定匹配算法進行介紹及Python代碼的實現,第一部分會針對穩定匹配的Gale-Shapley算法進行解析,第二部分就是用Python對該算法進行實現。
一、穩定匹配算法原理
1.1 介紹
穩定匹配(Stable Matching)問題就是假設現在有N個男生和N個女生跳舞選擇伴侶,然后最開始的時候男、女生按照下面情況對彼此進行排序選擇舞伴(見圖1):
- 每個男生都對女生按照最喜歡到最不喜歡進行排序;
- 同樣的,女生也是按照最喜歡的到最不喜歡對男生進行排序。
算法目標:每個男都找到唯一一個女舞伴,反之亦如此,從而達到了所謂的穩定匹配。
演示步驟:
1.2 偽代碼(Gale-Shapley Algorithm)
1 # 首先初始化所有男生的狀態為自由
2 initialize each person to be free
3
4 # 當男生沒有未曾被匹配過並且也沒有向所有其他女生尋求舞伴過時不斷循環
5 while some man m is not yet matched: 6 # 每個男生按照對女生的喜歡程度選擇舞伴 7 w := m's most favroite woman to whom he has not yet proposed 8 # 如果女生未被匹配到,則與男生進行配對 9 if w is also not yet matched: 10 w and m are paired 11 # 如果女生與已匹配的男生相比更喜歡當前的這個男生,則拆散重新匹配 12 elif w favors m to her current matched m': 13 w and m are paired and m' is dis-matched 14 # 否則該女生拒絕成為男生的舞伴 15 else: 16 w rejects m 17 # 返回所有匹配成功的舞伴對 18 return matched pairs
二、Python代碼實現
# -*- encoding: UTF-8 -*- import copy # 男的所期望的對象 manPrefers = dict((m, prefs.split(', ')) for [m, prefs] in (line.rstrip().split(': ') for line in open('men.txt'))) # 女的所期望的對象 womenPrefers = dict((m, prefs.split(', ')) for [m, prefs] in (line.rstrip().split(': ') for line in open('women.txt'))) men = sorted(manPrefers.keys()) women = sorted(womenPrefers.keys()) # 定義檢測函數檢測匹配的伴侶是否穩定 def check(engaged): inverseengaged = dict((v,k) for k,v in engaged.items()) for w, m in engaged.items(): shelikes = womenPrefers[w] shelikesbetter = shelikes[:shelikes.index(m)] helikes = manPrefers[m] helikesbetter = helikes[:helikes.index(w)] for man in shelikesbetter: womenOftheMan = inverseengaged[man] manLoves = manPrefers[man] if manLoves.index(womenOftheMan) > manLoves.index(w): print("%s 和 %s 更喜歡彼此相比起他們當前的伴侶: %s 和 %s" % (w, man, m, womenOftheMan)) return False for woman in helikesbetter: manOfTheWomen = engaged[woman] womanLoves = womenPrefers[woman] if womanLoves.index(manOfTheWomen) > womanLoves.index(m): print("%s 和 %s 更喜歡彼此相比起他們當前的伙伴:%s 和 %s" % (m, woman, w, manOfTheWomen)) return False return True def stableMatching(): free_men = men[:] engaged = {} manPref_temp = copy.deepcopy(manPrefers) womenPref_temp = copy.deepcopy(womenPrefers) while free_men: man = free_men.pop(0) manList = manPref_temp[man] woman = manList.pop(0) fiance = engaged.get(woman) if not fiance: engaged[woman] = man print(" %s 和 %s 成為伴侶" % (man, woman)) else: womenList = womenPref_temp[woman] if womenList.index(fiance) > womenList.index(man): engaged[woman] = man print(" %s 舍棄 %s 而和 %s 成為伴侶" % (woman, fiance, man)) if manPref_temp[fiance]: free_men.append(fiance) else: if manList: free_men.append(man) return engaged if __name__ == '__main__': print('\n伴侶匹配:') engaged = stableMatching() print('\n伴侶匹配:') print(' ' + ',\n '.join('%s 和 %s 成為伴侶' % couple for couple in sorted(engaged.items()))) print() print('伴侶穩定性檢測通過' if check(engaged) else '伴侶穩定性檢測不通過') print('\n\n因交換而產生伴侶搭配錯誤') engaged[women[0]], engaged[women[1]] = engaged[women[1]], engaged[women[0]] for woman in women[:2]: print(' %s 現在和 %s 成為伴侶' % (woman, engaged[woman])) print() print('伴侶穩定性檢測通過' if check(engaged) else '伴侶穩定性檢測不通過')