题目描述
模拟商场优惠打折,有三种优惠券可以用,满减券、打折券和无门槛券。
满减券:满100减10,满200减20,满300减30,满400减40,以此类推不限制使用;
打折券:固定折扣92折,且打折之后向下取整,每次购物只能用1次;
无门槛券:一张券减5元,没有使用限制。
每个人结账使用优惠券时有以下限制:
每人每次只能用两种优惠券,并且同一种优惠券必须一次用完,不能跟别的穿插使用(比如用一张满减,再用一张打折,再用一张满减,这种顺序不行)。
求不同使用顺序下每个人用完券之后得到的最低价格和对应使用优惠券的总数;如果两种顺序得到的价格一样低,就取使用优惠券数量较少的那个。
用例
暴力枚举
穷举所有合法组合:系统性地枚举所有可能的优惠券组合(3种组合 × 2种顺序)
最优解选择:在所有合法方案中选择价格最低的,价格相同时选择用券最少的
算法实现
def fullSubtraction(price, max_t):
"""
满减券:满100减10,满200减20,满300减30,满400减40,以此类推不限制使用;
"""
current_price = price
used_count = 0
for _ in range(max_t):
discount = (current_price // 100) * 10
if discount == 0: # 如果当前价格不满100,满减券无效
break
current_price -= discount
used_count += 1
return current_price, used_count
def discount(price):
"""
使用1张打折券
:param price: 原价
:return: 使用后的价格
"""
return int(price * 0.92)
def thresholdFree(price, k):
"""
使用k张无门槛券
:param price: 原价
:param k: 使用的无门槛券数量
:return: 使用后的价格
"""
price -= 5 * k
return max(price, 0)
def calculate_combo1(price, m, n):
"""组合1: 满减券 + 打折券"""
results = []
# 如果两种券都有,才考虑这个组合
if m > 0 and n > 0:
# 顺序A: 先满减后打折
p1, used_m1 = fullSubtraction(price, m) # 最多使用m张满减券
p1 = discount(p1)
count1 = used_m1 + 1
results.append((p1, count1))
# 顺序B: 先打折后满减
p2 = discount(price)
p2, used_m2 = fullSubtraction(p2, m) # 最多使用m张满减券
count2 = 1 + used_m2
results.append((p2, count2))
return results
def calculate_combo2(price, m, k):
"""组合2: 满减券 + 无门槛券"""
results = []
# 如果两种券都有,才考虑这个组合
if m > 0 and k > 0:
# 顺序A: 先满减后无门槛
p1, used_m1 = fullSubtraction(price, m) # 最多使用m张满减券
p1 = thresholdFree(p1, k)
count1 = used_m1 + k
results.append((p1, count1))
# 顺序B: 先无门槛后满减
p2 = thresholdFree(price, k)
p2, used_m2 = fullSubtraction(p2, m) # 最多使用m张满减券
count2 = k + used_m2
results.append((p2, count2))
return results
def calculate_combo3(price, n, k):
"""组合3: 打折券 + 无门槛券"""
results = []
# 如果两种券都有,才考虑这个组合
if n > 0 and k > 0:
# 顺序A: 先打折后无门槛
p1 = discount(price)
p1 = thresholdFree(p1, k)
count1 = 1 + k
results.append((p1, count1))
# 顺序B: 先无门槛后打折
p2 = thresholdFree(price, k)
p2 = discount(p2)
count2 = k + 1
results.append((p2, count2))
return results
def find_best_solution(price, m, n, k):
"""为单个顾客找到最优解决方案"""
best_price = price
best_count = 0
# 计算所有可能的组合
all_results = []
all_results.extend(calculate_combo1(price, m, n))
all_results.extend(calculate_combo2(price, m, k))
all_results.extend(calculate_combo3(price, n, k))
# 如果没有任何组合(比如券都用完了),返回原价
if not all_results:
return price, 0
# 找到最优解
for result_price, result_count in all_results:
if result_price < best_price or (result_price == best_price and result_count < best_count) or best_count == 0:
best_price = result_price
best_count = result_count
return best_price, best_count
def main():
"""主函数:处理输入和输出"""
# 读取输入
m, n, k = map(int, input().split())
x = int(input())
prices = [int(input()) for _ in range(x)]
# 为每个顾客计算最优方案
for price in prices:
best_price, best_count = find_best_solution(price, m, n, k)
print(best_price, best_count)
if __name__ == "__main__":
main()
注意网上还有一道类似的题:
题目描述
某网上商场举办优惠活动,发布了满减、打折、无门槛3种优惠券,分别为:
每满100元优惠10元,无使用数限制,如100~199元可以使用1张减10元,200~299可使用2张减20元,以此类推;
92折券,1次限使用1张,如100元,则优惠后为92元;
无门槛5元优惠券,无使用数限制,直接减5元。
优惠券使用限制
每次最多使用2种优惠券,2种优惠可以叠加(优惠叠加时以优惠后的价格计算),以购物200元为例,可以先用92折券优惠到184元,再用1张满减券优惠10元,最终价格是174元,也可以用满减券2张优惠20元为180元,再使用92折券优惠到165(165.6向下取整),不同使用顺序的优惠价格不同,以最优惠价格为准。在一次购物种,同一类型优惠券使用多张时必须一次性使用,不能分多次拆开使用(不允许先使用1张满减券,再用打折券,再使用一张满减券)。
问题
请设计实现一种解决方法,帮助购物者以最少的优惠券获得最优的优惠价格。优惠后价格越低越好,同等优惠价格,使用的优惠券越少越好,可以允许某次购物不使用优惠券。
约定
优惠活动每人只能参加一次,每个人的优惠券种类和数量是一样的。
用例
其中关于满减券的使用逻辑不同,导致最终实现也不同。本题和上面链接题目应该属于AB卷题目,防止作弊的。
模拟商场优惠打折,这题关于满减券的使用逻辑:
def fullSubtraction(price, max_t):
"""
每满100元优惠10元,无使用数限制,如100~199元可以使用1张减10元,200~299可使用2张减20元,以此类推;
:param price: 原价
:param max_t: 最多可使用的满减券数量
:return: (使用后的价格, 实际使用的券数)
"""
count = min((price // 100), max_t)
price -= count * 10
return price, count