11from dataclasses import dataclass
22from enum import Enum
3- from typing import List , Dict , Optional , Tuple
4- import itertools
3+ from typing import List , Dict , Optional
54import sys
65
76class OperatingSystem (Enum ):
87 MACOS = "macOS"
98 ARCH = "Arch Linux"
109 UBUNTU = "Ubuntu"
11-
1210@dataclass (frozen = True )
1311class Person :
1412 name : str
@@ -18,8 +16,6 @@ class Person:
1816# custom hash to hash the immutable version of the list
1917 def __hash__ (self ) -> int :
2018 return hash ((self .name , self .age , tuple (self .preferred_operating_system )))
21-
22-
2319@dataclass (frozen = True )
2420class Laptop :
2521 id : int
@@ -30,22 +26,23 @@ class Laptop:
3026
3127# =====define parse operating system======
3228def parse_operating_system (raw : str ) -> OperatingSystem :
33- normalized = raw .strip ().lower ()
29+ normalized = raw .strip ().lower ()
3430
35- aliases = {
36- "macos" : OperatingSystem .MACOS ,
37- "mac" : OperatingSystem .MACOS ,
38- "arch" : OperatingSystem .ARCH ,
39- "arch linux" : OperatingSystem .ARCH ,
40- "ubuntu" : OperatingSystem .UBUNTU ,
41- }
31+ aliases = {
32+ "macos" : OperatingSystem .MACOS ,
33+ "mac" : OperatingSystem .MACOS ,
34+ "arch" : OperatingSystem .ARCH ,
35+ "arch linux" : OperatingSystem .ARCH ,
36+ "ubuntu" : OperatingSystem .UBUNTU ,
37+ }
4238
43- if normalized not in aliases :
44- valid = ", " .join (sorted (aliases .keys ()))
45- print (f"Error: invalid operating system. Try one of: { valid } " , file = sys .stderr )
46- sys .exit (1 )
4739
48- return aliases [normalized ]
40+ if normalized not in aliases :
41+ valid = ", " .join (sorted (aliases .keys ()))
42+ print (f"Error: invalid operating system. Try one of: { valid } " , file = sys .stderr )
43+ sys .exit (1 )
44+
45+ return aliases [normalized ]
4946
5047# ======= sadness helper ============
5148def sadness (person : Person , laptop : Laptop ) -> int :
@@ -60,25 +57,30 @@ def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person
6057 if len (laptops ) < len (people ):
6158 raise ValueError ("Not enough laptops to allocate one per person." )
6259
63- best_assignment : Optional [Dict [Person , Laptop ]] = None
64- best_total_sadness : Optional [int ] = None
60+ sorted_people = sorted (people , key = lambda p : len (p .preferred_operating_system ))
61+
62+ remaining_laptops = laptops [:]
63+ assignment : Dict [Person , Laptop ] = {}
64+
65+ for person in sorted_people :
66+ best_laptop :Optional [Laptop ] = None
67+ best_score = 10 ** 9
6568
66- for chosen_laptops in itertools . combinations ( laptops , len ( people )) :
67- for permuted_laptops in itertools . permutations ( chosen_laptops ):
68- total = 0
69- for i in range ( len ( people )):
70- person = people [ i ]
71- laptop = permuted_laptops [ i ]
72- total += sadness ( person , laptop )
69+ for laptop in remaining_laptops :
70+ score = sadness ( person , laptop )
71+ if score < best_score :
72+ best_score = score
73+ best_laptop = laptop
74+ if score == 0 :
75+ break
7376
74- if best_total_sadness is None or total < best_total_sadness :
75- best_total_sadness = total
76- best_assignment = {people [i ]: permuted_laptops [i ] for i in range (len (people ))}
77+ if best_laptop is None :
78+ raise RuntimeError ("Allocation failed unexpectedly." )
7779
78- if best_assignment is None :
79- raise RuntimeError ( "Allocation failed unexpectedly." )
80+ assignment [ person ] = best_laptop
81+ remaining_laptops . remove ( best_laptop )
8082
81- return best_assignment
83+ return assignment
8284
8385# ======define main ================
8486def main () -> None :
0 commit comments