1. 小美的外卖订单
以下是整理后的内容,适合作为 CSDN 文章:
《小美外卖订单定价系统测试用例设计》
一、问题描述
小美正在设计美团外卖的定价信息,外卖定价规则如下:
- 每道菜有折扣价和原价,折扣价不能超过原价。
- 订单有满
x
元减y
元的优惠。当购买的菜的价格总和不小于x
元时,总价格可以减y
元。“减”的价格不能超过“满”的价格。 - 满减优惠和折扣价是互斥的,当且仅当每个菜都选择了原价才可以触发满减。
- 系统会自动为客户计算最低价格的方案。
在设计定价时,原价、折扣价和满减的价格都必须是正实数。如果设计的定价发生问题,则会提示数据错误。
二、输入输出描述
- 输入:
- 第一行输入一个正整数
n
,代表菜的总数。 - 接下来的
n
行,每行输入两个实数a_i
和b_i
,代表每道菜的原价是a_i
,折扣价是b_i
。 - 最后一行输入两个实数
x
和y
,代表满x
元可以减y
元。 - 约束条件:
1≤n≤10^5
,数据中所有实数的绝对值不超过 1000。
- 第一行输入一个正整数
- 输出:
- 如果数据有误,则输出一行字符串"error"。
- 否则输出一个小数,小数点后保留 2 位。该小数代表顾客购买了全部菜各一份时,订单的总价格。
三、示例说明
- 示例 1:
- 输入:
2
10 5.5
10 6.5
15 3
- 输出:
12.00
- 解释:虽然触发了满 15 元减 3 元,但使用折扣只需要花 12 元,低于使用满减的价格(20 - 3 = 17),因此最终系统会为客户推荐折扣价。
- 输入:
- 示例 2:
- 输入:
2
10 5.5
10 6.5
20 10
- 输出:
10.00
- 解释:触发满 20 元减 10 元即可。满减价优于折扣价。
- 输入:
- 示例 3:
- 输入:
2
10 10.25
10 3.5
20 4.5
- 输出:
error
- 解释:折扣价高于原价,数据错误。
- 输入:
四、测试用例设计思路(等价划分法)
- 针对每道菜的原价和折扣价关系进行划分:
- 折扣价小于原价,这是正常情况。
- 折扣价等于原价,也是合理情况。
- 折扣价大于原价,数据错误。
- 对于满减条件进行划分:
- “减”的价格小于“满”的价格,符合规则。
- “减”的价格等于“满”的价格,可以接受。
- “减”的价格大于“满”的价格,数据错误。
- 考虑菜的总数的边界情况:
n = 1
,只有一道菜的情况。n = 10^5
,最大菜的总数情况。
五、代码实现
以下是使用 Python 实现的代码:
n = int(input())
dishes = []
for _ in range(n):
a, b = map(float, input().split())
dishes.append((a, b))
x, y = map(float, input().split())
# 检查折扣价是否合法
for a, b in dishes:
if b > a:
print("error")
break
# 隐藏条件:如果有数字小于0也是错误的
if a < 0 or b < 0 :
print("error")
break
else:
# 计算原价总和
original_total = sum(a for a, _ in dishes)
# 计算折扣价总和
discount_total = sum(b for _, b in dishes)
# 满减后的价格
if original_total >= x:
minus_total = original_total - y
else:
minus_total = original_total
if minus_total < discount_total:
print(f"{minus_total:.2f}")
else:
print(f"{discount_total:.2f}")
以上代码只能通过15/20的用例,很显然是没满足题目中的隐藏条件。
再输入x、y
后添加代码检查x、y
是否符合要求:
n = int(input())
dishes = []
for _ in range(n):
a, b = map(float, input().split())
dishes.append((a, b))
x, y = map(float, input().split())
if x < 0 or y < 0:
print("error")
else:
# 检查折扣价是否合法
for a, b in dishes:
if b > a:
print("error")
break
if a < 0 or b < 0 :
print("error")
break
else:
# 计算原价总和
original_total = sum(a for a, _ in dishes)
# 计算折扣价总和
discount_total = sum(b for _, b in dishes)
# 满减后的价格
if original_total >= x:
minus_total = original_total - y
else:
minus_total = original_total
if minus_total < discount_total:
print(f"{minus_total:.2f}")
else:
print(f"{discount_total:.2f}")
也仅仅是提升到了17/20
查看用例,发现是x一定要大于y:
所以继续加条件
x, y = map(float, input().split())
if x < 0 or y < 0:
print("error")
elif x < y:
print("error")
发现测试用例又通过了一个
继续看测试用例,发现这次的用例中有个b为0…天底下哪有免费的午餐,
略作修改,
else:
# 检查折扣价是否合法
for a, b in dishes:
if b > a:
print("error")
break
if a <= 0 or b <= 0 :
print("error")
break
else:
又多通过了一个…还差最后一个,有点无语了真的。
最后一个y为0了,
所以
n = int(input())
dishes = []
for _ in range(n):
a, b = map(float, input().split())
dishes.append((a, b)) # 列表中每个位置放置二元数组
x, y = map(float, input().split())
# 检查输入的合法性
if x < 0 or y <= 0:
print("error")
elif x < y:
print("error")
else:
# 检查折扣价是否合法
for a, b in dishes:
if b > a:
print("error")
break
if a <= 0 or b <= 0 :
print("error")
break
else:
# 计算原价总和
original_total = sum(a for a, _ in dishes)
# 计算折扣价总和
discount_total = sum(b for _, b in dishes)
# 满减后的价格
if original_total >= x:
minus_total = original_total - y
else:
minus_total = original_total
if minus_total < discount_total:
print(f"{minus_total:.2f}")
else:
print(f"{discount_total:.2f}")
至此全部用例全部通过
总结:没考虑清楚实际情况,天底下没有免费的午餐这回事,
语法方面:
- sum(b for _, b in dishes)
:一种在 Python 中使用生成器表达式并结合sum
函数进行求和的写法。
具体解释如下:
-
dishes
是一个列表,其中的每个元素是一个二元组,比如(a, b)
,可能代表一道菜的原价和折扣价。 -
_, b in dishes
这里使用了一种特殊的语法,_
通常在 Python 中作为一个临时的、不关心其具体值的变量名。在这个上下文中,通过这种方式遍历dishes
列表中的每个二元组,提取出每个二元组中的第二个元素(即折扣价b
)。 -
b for _, b in dishes
这部分是一个生成器表达式,它会生成一个由每个二元组中的折扣价组成的序列。 -
sum(b for _, b in dishes)
最后,使用sum
函数对这个生成器表达式生成的序列进行求和,也就是求所有菜的折扣价之和。
例如,如果dishes = [(10, 5), (15, 8), (20, 10)]
,那么sum(b for _, b in dishes)
就会计算5 + 8 + 10
的值。
- for _ in range(n)
是一种常见的循环结构。
-
range(n)
会生成一个从 0 到n - 1
的整数序列。例如,如果n = 5
,那么range(n)
会生成序列0, 1, 2, 3, 4
。 -
for _ in...
这里的_
通常用作一个临时的、不关心其具体值的变量名。当你只是需要循环特定次数而不需要在循环体内使用循环变量的具体值时,可以使用_
。
例如,以下代码会循环 n
次:
n = 5
for _ in range(n):
print("这是一次循环")
这段代码会打印“这是一次循环”五次,而在循环体内没有使用到循环变量的值,所以使用 _
来表示这个不关心其具体值的变量。
- Python 中使用 f-string(格式化字符串字面量)来输出一个带有特定格式的数值。
具体解释如下:
-
f"{minus_total:.2f}"
中的f
表示这是一个 f-string。在 f-string 中,可以直接在花括号{}
内插入变量、表达式等,并进行格式化输出。 -
minus_total
是一个要输出的数值变量。 -
:.2f
是一个格式说明符,用于指定输出的格式。在这里,.2f
表示将数值格式化为保留两位小数的浮点数。
例如,如果 minus_total = 12.3456
,那么执行 print(f"{minus_total:.2f}")
会输出 12.35
。