1
- # Explanation:- https://en.wikipedia.org/wiki/Set_cover_problem
1
+ # https://en.wikipedia.org/wiki/Set_cover_problem
2
2
3
3
from dataclasses import dataclass
4
+ from operator import attrgetter
4
5
5
6
6
7
@dataclass
7
8
class Item :
8
9
weight : int
9
10
value : int
10
11
12
+ @property
13
+ def ratio (self ) -> float :
14
+ """
15
+ Return the value-to-weight ratio for the item.
16
+
17
+ Returns:
18
+ float: The value-to-weight ratio for the item.
19
+
20
+ Examples:
21
+ >>> Item(10, 65).ratio
22
+ 6.5
23
+
24
+ >>> Item(20, 100).ratio
25
+ 5.0
26
+
27
+ >>> Item(30, 120).ratio
28
+ 4.0
29
+ """
30
+ return self .value / self .weight
31
+
11
32
12
33
def fractional_cover (items : list [Item ], capacity : int ) -> float :
13
34
"""
14
35
Solve the Fractional Cover Problem.
15
36
16
37
Args:
17
- items (List[Item]): A list of items, where each item is represented as an
18
- Item object with weight and value attributes.
19
- capacity (int): The maximum weight capacity of the knapsack.
38
+ items: A list of items, where each item has weight and value attributes.
39
+ capacity: The maximum weight capacity of the knapsack.
20
40
21
41
Returns:
22
- float: The maximum value that can be obtained by selecting fractions of items to
23
- cover the knapsack's capacity.
42
+ The maximum value that can be obtained by selecting fractions of items to cover
43
+ the knapsack's capacity.
24
44
25
45
Raises:
26
- ValueError: If the ` capacity` is negative.
46
+ ValueError: If capacity is negative.
27
47
28
48
Examples:
29
- >>> items = [Item(10, 60), Item(20, 100), Item(30, 120)]
30
- >>> fractional_cover(items, 50)
49
+ >>> fractional_cover((Item(10, 60), Item(20, 100), Item(30, 120)), capacity=50)
31
50
240.0
32
51
33
- >>> items = [Item(20, 100), Item(30, 120), Item(10, 60)]
34
- >>> fractional_cover(items, 25)
52
+ >>> fractional_cover([Item(20, 100), Item(30, 120), Item(10, 60)], capacity=25)
35
53
135.0
36
54
37
- >>> items = [Item(10, 60), Item(20, 100), Item(30, 120)]
38
- >>> fractional_cover(items, 60)
55
+ >>> fractional_cover([Item(10, 60), Item(20, 100), Item(30, 120)], capacity=60)
39
56
280.0
40
57
41
- >>> items = [Item(5, 30), Item(10, 60), Item(15, 90)]
42
- >>> fractional_cover(items, 30)
58
+ >>> fractional_cover(items=[Item(5, 30), Item(10, 60), Item(15, 90)], capacity=30)
43
59
180.0
44
60
45
- >>> items = []
46
- >>> fractional_cover(items, 50)
61
+ >>> fractional_cover(items=[], capacity=50)
47
62
0.0
48
63
49
- >>> items = [Item(10, 60)]
50
- >>> fractional_cover(items, 5)
64
+ >>> fractional_cover(items=[Item(10, 60)], capacity=5)
51
65
30.0
52
66
53
- >>> items = [Item(10, 60)]
54
- >>> fractional_cover(items, 1)
67
+ >>> fractional_cover(items=[Item(10, 60)], capacity=1)
55
68
6.0
56
69
57
- >>> items = [Item(1, 1)]
58
- >>> fractional_cover(items, 0)
70
+ >>> fractional_cover(items=[Item(10, 60)], capacity=0)
59
71
0.0
60
72
61
- >>> items = [Item(10, 60)]
62
- >>> fractional_cover(items, -1)
73
+ >>> fractional_cover(items=[Item(10, 60)], capacity=-1)
63
74
Traceback (most recent call last):
64
75
...
65
76
ValueError: Capacity cannot be negative
66
77
"""
67
78
if capacity < 0 :
68
79
raise ValueError ("Capacity cannot be negative" )
69
- # Calculate the value-to-weight ratios for each item
70
- ratios = [(item .value / item .weight , item ) for item in items ]
71
-
72
- # Sort the items by their value-to-weight ratio in descending order
73
- ratios .sort (key = lambda item_ratio : item_ratio [0 ], reverse = True )
74
80
75
81
total_value = 0.0
76
82
remaining_capacity = capacity
77
83
78
- for ratio , item in ratios :
84
+ # Sort the items by their value-to-weight ratio in descending order
85
+ for item in sorted (items , key = attrgetter ("ratio" ), reverse = True ):
79
86
if remaining_capacity == 0 :
80
87
break
81
88
82
89
weight_taken = min (item .weight , remaining_capacity )
83
- total_value += weight_taken * ratio
90
+ total_value += weight_taken * item . ratio
84
91
remaining_capacity -= weight_taken
85
92
86
93
return total_value
@@ -89,8 +96,7 @@ def fractional_cover(items: list[Item], capacity: int) -> float:
89
96
if __name__ == "__main__" :
90
97
import doctest
91
98
92
- result = doctest .testmod ().failed
93
- if result == 0 :
94
- print ("All tests passed" )
95
- else :
99
+ if result := doctest .testmod ().failed :
96
100
print (f"{ result } test(s) failed" )
101
+ else :
102
+ print ("All tests passed" )
0 commit comments