题解 | #自动售货系统# #动态规划# 最折磨的一集
自动售货系统
https://www.nowcoder.com/practice/cd82dc8a4727404ca5d32fcb487c50bf
import sys
from dataclasses import dataclass
from typing import List
@dataclass
class Goods:
name: str
price: int
quantity: int
coins = (1, 2, 5, 10)
class Machine:
def __init__(self):
self.goods: List[Goods] = [Goods(f"A{x}", x + 1, 0) for x in range(1, 5)] + [
Goods("A5", 8, 0),
Goods("A6", 6, 0),
]
self.coin_box: List[int] = []
self.balance: int = 0
def init(self, goods_quantity: List[int], coins_qunatity: List[int]) -> str:
for good, qty in zip(self.goods, goods_quantity):
good.quantity = qty
for index, qty in enumerate(coins_qunatity):
self.coin_box += [coins[index]] * qty
return "S001:Initialization is successful"
def is_sold_out(self) -> bool:
# 如果卖完就返回true
return all(good.quantity == 0 for good in self.goods)
def sum_of_one_two(self) -> int:
return self.coin_box.count(1) + 2*self.coin_box.count(2)
def insert_coin(self, amount: int) -> str:
if amount not in {1, 2, 5, 10}: # 不为指定面额
return "E002:Denomination error"
if self.sum_of_one_two() < amount:
return "E003:Change is not enough, pay fail"
if self.is_sold_out(): # 卖完
return "E005:All the goods sold out"
self.balance += amount
self.coin_box.append(amount)
return f"S002:Pay success,balance={self.balance}"
def purchase(self, good: str) -> str:
for x in self.goods:
if x.name == good:
if x.quantity == 0: # 数量为0
return "E007:The goods sold out"
if self.balance < x.price: # 钱不够
return "E008:Lack of balance"
# 购买商品成功后,自动售货机中对应商品数量减1,投币余额扣除本次购买商品的价格。
x.quantity -= 1
self.balance -= x.price
return f"S003:Buy success,balance={self.balance}"
return "E006:Goods does not exist"
def return_cash(self) -> str:
if self.balance == 0:
return "E009:Work failure"
# 按钱币总张数最少的原则进行退币
# 如果因零钱不足导致不能退币,则尽最大可能退币
tmp = [()] * (self.balance+1)
self.coin_box = sorted(self.coin_box, reverse=True)
for x in self.coin_box:
for index, comb in enumerate(tmp):
if comb == () and index != 0:
continue
new_amount = index + x
if new_amount > self.balance:
continue
if tmp[new_amount] != ():
if len(tmp[new_amount]) > len(comb) + 1:
tmp[new_amount] = tuple(comb) + (x,)
else:
tmp[new_amount] = tuple(comb) + (x,)
for x in reversed(tmp):
if x != ():
# 从零钱中删除该组合
# 清零balance
for y in x:
self.coin_box.remove(y)
self.balance = 0
return self.return_coins_str(x)
def return_goods_str(self):
return "\n".join(f"{x.name} {x.price} {x.quantity}" for x in self.goods)
def return_coins_str(self,coin):
return '\n'.join(f"{x} yuan coin number={coin.count(x)}" for x in coins)
def return_self_coins_str(self):
return self.return_coins_str(self.coin_box)
def solve_cmd(cmd: str, machine: Machine):
#分析解后的命令 例如 p 1
content = cmd.split()
result = 'E010:Parameter error'
if len(content) == 1 and content[0] == 'c':
result = machine.return_cash()
if content[0] == 'r':
result = machine.init(list(map(int,content[1].split('-'))), list(map(int,content[2].split('-'))))
if content[0]=='p':
result = machine.insert_coin(int(content[1]))
if content[0]=='b':
result = machine.purchase(content[1])
if content[0]=='q':
if content[1] == '0':
result = machine.return_goods_str()
elif content[1] == '0':
result = machine.return_goods_str()
return result
machine = Machine()
command = input().split(';')
for x in command:
if x:
print(solve_cmd(x,machine))
需要用动态规划计算每个数值的最小可能组合,最好是逆序从最大的面值开始找起,为以防找不到组合,把动态规划的列表进行一个逆序输出。输出答案的时候不要忘记把余额清零,零钱也不要忘去除。
最折磨的苦力题目
