付账问题

题干

解题思路

这是一道关于优化付款方案以实现最小标准差的问题,解题关键在于合理分配每个人的付款金额。

这道题的贪心策略是优先从带钱少的人开始分配付款金额,让每个人在自身能力范围内承担尽可能多的费用,以使得所有人付款金额的标准差最小。

具体来说:

  • 对所有人带钱数升序排序后,先处理带钱少的人。当某人带的钱数小于当前剩余人平均需支付金额时,就让他把全部钱都用于付款,因为若让其支付少于所带金额,后续其他人可能需支付更多,会增大支付差异,不利于减小标准差。

  • 当遇到某人带的钱数大于等于当前剩余人平均需支付金额时,说明剩下的人都能按此平均金额支付,此时已实现局部最优分配,能保证整体标准差最小。

算法步骤:

  1. 处理输入:

  • 读取第一行输入的两个整数 nS,分别代表人数和总消费金额。

  • 读取第二行输入的 n 个非负整数,存入列表 a 中,表示每个人所带的钱数。

  • 将列表 a 按升序排序,方便后续从带钱少的人开始处理。

  1. 计算初始平均付款金额:

计算所有人平均需要支付的金额 average = S / n,这是整体付款的一个基准数值。

  1. 迭代分配付款金额:

从带钱最少的人开始遍历列表 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 中,然后停止迭代。因为从带钱少的人开始处理,到这一步已经能保证整体付款分配使标准差最小。

  1. 计算并输出标准差:

根据标准差公式 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))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值