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