2025-10-03 10:40:05 -04:00
|
|
|
"""
|
|
|
|
|
name: Nicholas Tamassia
|
|
|
|
|
|
|
|
|
|
Honor Code and Acknowledgments:
|
|
|
|
|
|
|
|
|
|
This work complies with the JMU Honor Code.
|
|
|
|
|
|
|
|
|
|
Comments here on your code and submission.
|
|
|
|
|
"""
|
|
|
|
|
|
2025-10-05 15:31:05 -04:00
|
|
|
from dataclasses import dataclass
|
2025-10-05 22:26:44 -04:00
|
|
|
from typing import Self, override
|
2025-10-05 15:31:05 -04:00
|
|
|
|
|
|
|
|
|
2025-10-05 22:26:44 -04:00
|
|
|
# I don't like tuples, dataclasses ftw
|
2025-10-05 15:31:05 -04:00
|
|
|
@dataclass(frozen=True)
|
|
|
|
|
class KnapsackItem:
|
|
|
|
|
name: str
|
|
|
|
|
value: float
|
|
|
|
|
weight: float
|
|
|
|
|
|
|
|
|
|
@property
|
2025-10-05 22:26:44 -04:00
|
|
|
def value_ratio(self) -> float:
|
2025-10-05 15:31:05 -04:00
|
|
|
return self.value / self.weight
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
def __str__(self) -> str:
|
|
|
|
|
return f"{self.name}({self.value:.2f}, {self.weight:.2f})"
|
|
|
|
|
|
2025-10-05 22:26:44 -04:00
|
|
|
@classmethod
|
|
|
|
|
def parse(cls, string: str) -> Self:
|
|
|
|
|
values: list[str] = string.strip().split()
|
2025-10-05 15:31:05 -04:00
|
|
|
name, value, weight = values[0], float(values[1]), float(values[2])
|
2025-10-05 22:26:44 -04:00
|
|
|
return cls(name, value, weight)
|
2025-10-05 15:31:05 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def knapsack(
|
|
|
|
|
capacity: int, items: list[KnapsackItem]
|
|
|
|
|
) -> tuple[list[KnapsackItem], float]:
|
2025-10-05 22:26:44 -04:00
|
|
|
|
|
|
|
|
current_capacity: float = float(capacity)
|
|
|
|
|
sorted_items: list[KnapsackItem] = sorted(items, key=lambda i: -i.value_ratio)
|
2025-10-05 15:31:05 -04:00
|
|
|
|
|
|
|
|
total_value: float = 0.0
|
|
|
|
|
fractional_items: list[KnapsackItem] = []
|
|
|
|
|
|
|
|
|
|
for item in sorted_items:
|
2025-10-05 22:26:44 -04:00
|
|
|
if abs(current_capacity) < 1e-8:
|
2025-10-05 15:31:05 -04:00
|
|
|
break
|
|
|
|
|
|
2025-10-05 22:26:44 -04:00
|
|
|
name, value, weight = item.name, item.value, item.weight
|
|
|
|
|
if current_capacity < weight:
|
|
|
|
|
value = item.value_ratio * current_capacity
|
|
|
|
|
weight = current_capacity
|
|
|
|
|
|
|
|
|
|
fractional_items.append(KnapsackItem(name, value, weight))
|
|
|
|
|
total_value += value
|
|
|
|
|
current_capacity -= weight
|
2025-10-05 15:31:05 -04:00
|
|
|
|
|
|
|
|
return fractional_items, total_value
|
|
|
|
|
|
2025-10-03 10:40:05 -04:00
|
|
|
|
|
|
|
|
# All modules for CS 412 must include a main method that allows it
|
|
|
|
|
# to imported and invoked from other python scripts
|
|
|
|
|
def main():
|
2025-10-05 15:31:05 -04:00
|
|
|
capacity: int = int(input())
|
|
|
|
|
n: int = int(input())
|
|
|
|
|
|
2025-10-05 22:26:44 -04:00
|
|
|
items: list[KnapsackItem] = [KnapsackItem.parse(input()) for _ in range(0, n)]
|
2025-10-05 15:31:05 -04:00
|
|
|
|
|
|
|
|
fractional_items, total_value = knapsack(capacity, items)
|
|
|
|
|
|
|
|
|
|
print(" ".join(map(str, fractional_items)))
|
|
|
|
|
print(total_value)
|
2025-10-03 10:40:05 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|