fkudinov

9. Задача Пакування Рюкзака / Задачі на Python / Острів Ешера

Nov 14th, 2024
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.95 KB | Source Code | 0 0
  1. # --------------     tasks/escher_tasks/task_9__treasures.py   ----------------
  2.  
  3.  
  4. def treasures(info, limit):
  5.  
  6.     limit = int(limit * 1000)
  7.     keys = sorted(info,
  8.                   key=lambda k: info[k]["price"] / info[k]["weight"],
  9.                   reverse=True)
  10.  
  11.     res = {}
  12.     for k in keys:
  13.         can_take = limit // info[k]["weight"]
  14.         will_take = min(can_take, info[k]["amount"])
  15.         res[k] = will_take
  16.         limit -= will_take * info[k]["weight"]
  17.  
  18.     return [f"{k}: {res[k]}" for k in info if res[k] > 0]
  19.  
  20.  
  21. from itertools import product
  22.  
  23.  
  24. def treasures_2(info, limit):
  25.  
  26.     limit = int(limit * 1000)
  27.  
  28.     counts = {}
  29.     for k in info:
  30.         can_put = limit // info[k]["weight"]
  31.         will_put = min(can_put, info[k]["amount"])
  32.         counts[k] = will_put
  33.  
  34.     res = [0 for _ in info]
  35.     best_price = 0
  36.  
  37.     for combination in product(*[range(counts[k] + 1) for k in info]):
  38.         total_price = sum([amount * info[k]["price"]
  39.                            for k, amount in zip(info, combination)])
  40.         total_weight = sum([amount * info[k]["weight"]
  41.                             for k, amount in zip(info, combination)])
  42.  
  43.         if total_weight <= limit and total_price > best_price:
  44.             res = combination
  45.             best_price = total_price
  46.  
  47.     return [f"{k}: {count}" for k, count in zip(info, res) if count]
  48.  
  49.  
  50. def treasures_3(info, limit):
  51.  
  52.     limit = int(limit * 1000)
  53.     best_results = [[0 for _ in info]]
  54.  
  55.     for i in range(1, limit + 1):
  56.         results = [best_results[-1].copy()]
  57.  
  58.         for _idx, k in enumerate(info):
  59.             if i < info[k]["weight"]:
  60.                 continue
  61.  
  62.             res = best_results[i - info[k]["weight"]].copy()
  63.             res[_idx] += 1
  64.             if res[_idx] > info[k]["amount"]:
  65.                 continue
  66.             results.append(res)
  67.  
  68.         get_price = lambda res: sum(i * info[k]["price"]
  69.                                     for i, k in zip(res, info))
  70.         best_results.append(max(results, key=get_price))
  71.  
  72.     return [f"{k}: {i}" for k, i in zip(info, best_results[-1]) if i]
  73.  
  74.  
  75. # ----------------  tests/test_escher_tasks/test_task_9__treasures.py ------------------
  76.  
  77.  
  78. import pytest
  79. from tasks.escher_tasks.task_9__treasures import (
  80.     treasures, treasures_2, treasures_3)
  81.  
  82.  
  83. @pytest.mark.parametrize("func", [treasures, treasures_2, treasures_3])
  84. def test_treasures(func):
  85.  
  86.     assert func(
  87.         {'golden coin': {'price': 100, 'weight': 50, 'amount': 200},
  88.          'silver coin': {'price': 10, 'weight': 20, 'amount': 1000},
  89.          'ruby': {'price': 1000, 'weight': 200, 'amount': 2}}, 5
  90.     ) == ['golden coin: 92', 'ruby: 2']
  91.  
  92.     assert func(
  93.         {'golden coin': {'price': 100, 'weight': 50, 'amount': 100},
  94.          'silver coin': {'price': 10, 'weight': 20, 'amount': 100},
  95.          'ruby': {'price': 1000, 'weight': 200, 'amount': 1}}, 7.5
  96.     ) == ['golden coin: 100', 'silver coin: 100', 'ruby: 1']
  97.  
Add Comment
Please, Sign In to add comment