@@ -44,33 +44,41 @@ def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person
4444 if len (people ) != len (laptops ):
4545 raise ValueError ("Number of people must equal number of laptops" )
4646
47- # Greedy approach: Sort people by how limited their good options are
48- # Then allocate their best available choice
4947 allocation : Dict [Person , Laptop ] = {}
50- available_laptops = list (laptops )
48+ available_laptops = set (laptops ) # Use set for O(1) lookup and removal
5149
52- # Create a priority queue of (person, laptop, sadness) tuples
53- # Sort by sadness to allocate best matches first
54- preferences = []
55- for person in people :
50+ # Helper to find best available laptop for a person
51+ def find_best_available (person : Person ) -> tuple [Laptop , int ] | None :
52+ """Returns (best_laptop, sadness) or None if no laptops available."""
53+ best_laptop = None
54+ best_sadness = float ('inf' )
55+
5656 for laptop in available_laptops :
5757 sadness = calculate_sadness (person , laptop )
58- preferences .append ((sadness , person , laptop ))
58+ if sadness < best_sadness :
59+ best_sadness = sadness
60+ best_laptop = laptop
61+ # Early exit if we found a perfect match (sadness 0)
62+ if sadness == 0 :
63+ break
64+
65+ return (best_laptop , best_sadness ) if best_laptop else None
5966
60- preferences .sort (key = lambda x : x [0 ])
67+ # Sort people by how limited their good options are
68+ # (by counting how many laptops match their preferences - less matches = higher priority)
69+ def count_good_matches (person : Person ) -> int :
70+ """Count how many laptops have sadness < 100 (i.e., OS is in their preferences)."""
71+ return sum (1 for laptop in laptops if calculate_sadness (person , laptop ) < 100 )
6172
62- # Greedy allocation: try to give everyone their best available choice
63- allocated_people = []
64- allocated_laptops = []
73+ sorted_people = sorted (people , key = count_good_matches )
6574
66- for sadness , person , laptop in preferences :
67- if person not in allocated_people and laptop not in allocated_laptops :
75+ # Greedy allocation: for each person, find their best available laptop
76+ for person in sorted_people :
77+ result = find_best_available (person )
78+ if result :
79+ laptop , _ = result
6880 allocation [person ] = laptop
69- allocated_people .append (person )
70- allocated_laptops .append (laptop )
71-
72- if len (allocation ) == len (people ):
73- break
81+ available_laptops .remove (laptop ) # O(1) removal
7482
7583 return allocation
7684
@@ -96,9 +104,11 @@ def calculate_total_sadness(allocation: Dict[Person, Laptop]) -> int:
96104allocation = allocate_laptops (people , laptops )
97105
98106print ("Laptop Allocation:" )
107+ total_sadness = 0
99108for person , laptop in allocation .items ():
100109 sadness = calculate_sadness (person , laptop )
110+ total_sadness += sadness
101111 print (f"{ person .name } -> { laptop .manufacturer } { laptop .model } ({ laptop .operating_system .value } ) - Sadness: { sadness } " )
102112
103- print (f"\n Total Sadness: { calculate_total_sadness ( allocation ) } " )
113+ print (f"\n Total Sadness: { total_sadness } " )
104114
0 commit comments