题干
解题思路
这是一道关于优化付款方案以实现最小标准差的问题,解题关键在于合理分配每个人的付款金额。
这道题的贪心策略是优先从带钱少的人开始分配付款金额,让每个人在自身能力范围内承担尽可能多的费用,以使得所有人付款金额的标准差最小。
具体来说:
-
对所有人带钱数升序排序后,先处理带钱少的人。当某人带的钱数小于当前剩余人平均需支付金额时,就让他把全部钱都用于付款,因为若让其支付少于所带金额,后续其他人可能需支付更多,会增大支付差异,不利于减小标准差。
-
当遇到某人带的钱数大于等于当前剩余人平均需支付金额时,说明剩下的人都能按此平均金额支付,此时已实现局部最优分配,能保证整体标准差最小。
算法步骤:
-
处理输入:
-
读取第一行输入的两个整数
n
和S
,分别代表人数和总消费金额。 -
读取第二行输入的
n
个非负整数,存入列表a
中,表示每个人所带的钱数。 -
将列表
a
按升序排序,方便后续从带钱少的人开始处理。
-
计算初始平均付款金额:
计算所有人平均需要支付的金额 average = S / n
,这是整体付款的一个基准数值。
-
迭代分配付款金额:
从带钱最少的人开始遍历列表 a
:
-
计算当前剩余
n - i
个人时的平均付款金额new_ave = S / (n - i)
。 -
比较当前人带的钱数a[i] 和 new_ave,分为两种情况:
-
若
a[i] < new_ave
,说明此人带的钱不足以支付当前平均金额,那就让他把所有钱都拿出来付款。此时将(average - a[i]) ** 2
累加到ans
中(ans
用于累加偏差平方和),同时更新总消费金额S = S - a[i]
。这样做的原因是先让支付能力弱的人尽可能贡献,后续能更好地平衡整体付款情况。 -
若
a[i] >= new_ave
,表明此人带的钱足够支付当前平均金额,那么剩下的人都可以按new_ave
来付款。此时将(n - i) * (new_ave - average) ** 2
累加到ans
中,然后停止迭代。因为从带钱少的人开始处理,到这一步已经能保证整体付款分配使标准差最小。
-
-
计算并输出标准差:
根据标准差公式 res = (ans / n) ** 0.5
算出标准差,并将结果四舍五入保留 4 位小数后输出。
这种思路基于贪心策略,优先考虑带钱少的人的付款情况,逐步调整整体付款分配,以达到使标准差最小的目的。
解题代码
# n表示有多少人,s表示总共需要多少钱
n , s = map(int,input().split())
# a表示每个人带的钱
a = list( map( int , input().split() ) )
# 升序排序
a.sort()
# 计算每个人平均需要交的钱
average = s / n
ans = 0
for i in range(n):
new_ave = s / (n - i)
# 如果这个人的钱不足以交现在的平均值,那么这个人需要把所有钱都上交
if a[i] < new_ave:
ans = ans + (average - a[i])**2
s = s - a[i]
else:
# 如果这个人的钱足够交平均值,那么剩下的人都需要交平均值的钱
ans = ans + (n-i)*(new_ave - average)**2
break
# 计算标准差 四舍五入保留4位小数
res = (ans / n) ** 0.5
print("{:.4f}".format(res))