1+ """
2+ The Gale-Shapley algorithm is a method to solve the
3+ stable matching/marriage problem. Given N men and women
4+ with ranked preferences of the opposite sex, the men and
5+ women will be matched so that each pair of man and woman
6+ would not prefer someone over their current match. With
7+ no conflicting preferences, the matches are stable. The
8+ algorithm can be extended to issues that involve ranked
9+ matching.
10+
11+ Example for function:
12+ M denotes man, W denotes woman, and number corresponds to
13+ respective man/woman. Preference lists go from highest to lowest.
14+
15+ men_preferences = {
16+ "M1": ["W1", "W2", "W3"],
17+ "M2": ["W1", "W3", "W2"],
18+ "M3": ["W3", "W1", "W2"],
19+ }
20+ women_preferences = {
21+ "W1": ["M2", "M1", "M3"],
22+ "W2": ["M1", "M2", "M3"],
23+ "W3": ["M3", "M1", "M2"],
24+ }
25+
26+ input: print(gale_shapley(men_preferences, women_preferences))
27+ output: {'M2': 'W1', 'M3': 'W3', 'M1': 'W2'}
28+ Explanation:
29+ Both Man 1 and Man 2 have a top preference of Woman 1,
30+ and since Woman 1 has a top preference of Man 2, Man 2
31+ and Woman 1 are matched, and Man 1 is added back to available
32+ men. Man 3 and Woman 3 have their top preference as each other,
33+ so the two are matched. Man 1 then proposes to Woman 2, and
34+ Man 1 is the top preference of Woman 2, so the two are matched.
35+ There is no match of Man AND Woman where both would want to
36+ leave, so the current matches are stable.
37+
38+ """
39+
40+ # size denotes the number of men/women
41+ # Function takes in dictionary for men and women preferences in style outlined above
42+ def gale_shapley (men , women ):
43+ size = len (men )
44+ # Initialize all men to be available
45+ men_available = list (men .keys ())
46+ # Initialize married to empty
47+ married = {}
48+ # Intialize proposal count for each man to 0
49+ proposal_counts = {man : 0 for man in men }
50+ while men_available :
51+ # Pop first available man
52+ man = men_available .pop (0 )
53+ # Of the popped man, set woman equal to corresponding proposal index
54+ woman = men [man ][proposal_counts [man ]]
55+ #increment proposal count
56+ proposal_counts [man ] += 1
57+ if woman not in married :
58+ # Set marriage if woman not married
59+ married [woman ] = man
60+ else :
61+ # If woman married, currently_married corresponds to currently matched man
62+ currently_married = married [woman ]
63+ if women [woman ].index (man ) < women [woman ].index (currently_married ):
64+ """
65+ If the available man is of greater preference to the woman than her
66+ currently married partner, change the marriage to the new available
67+ man and append the previously married man back to men_available
68+ """
69+ married [woman ] = man
70+ men_available .append (currently_married )
71+ else :
72+ # Add man back to men_available and try woman at next index
73+ men_available .append (man )
74+ # Returns pairs of matched men and women in form of Man:Woman
75+ return {man : woman for woman , man in married .items ()}
76+
77+ # Example case
78+ men_preferences = {
79+ "M1" : ["W1" , "W2" , "W3" ],
80+ "M2" : ["W1" , "W3" , "W2" ],
81+ "M3" : ["W3" , "W1" , "W2" ],
82+ }
83+ women_preferences = {
84+ "W1" : ["M2" , "M1" , "M3" ],
85+ "W2" : ["M1" , "M2" , "M3" ],
86+ "W3" : ["M3" , "M1" , "M2" ],
87+ }
88+
89+ res = gale_shapley (men_preferences , women_preferences )
90+ print (res )
0 commit comments