抢红包算法模拟
本篇内容为抢随机红包模拟算法,仅供参考。
方法
本篇使用的是二倍均值法,在此之前,先大概讲下普通随机法。
普通随机方法
该方法的原理是:每次都以 [最小值,剩余金额值]
之间进行随机取值。
假设红包金额为 88.88
,红包数量为 8
个,那么第一个人领取金额将从 [0.01, 88.88]
之间进行取值,假设取值为 20.20
,那么剩余的金额为 68.68
。
第二个领取金额将从 [0,01, 68.68]
之间进行取值,以此类推...
这里可以明显看出此方法的弊端,前面领取红包的金额区间更大,也就更容易获取更大的红包金额。下面看二倍均值法的原理。
二倍均值法
方法实现的原理是:每次以 [最小值,红包剩余金额 / 人数 * 2]
的区间进行取值。
假设红包金额为 88.88
,红包数量为 8
个,理想情况下,方法的实现效果:
第一个人领取红包金额区间为 [0.01, 88.88 / 8 * 2]
,即是 [0.01, 22.22]
之间随机获取金额数。假设取平均值 11.11
,则剩余金额 77.77
;
第二个人领取红包金额区间为 [0.01, 77.77 / 7 * 2]
,即是 [0.01, 22.22]
之间随机获取金额数。假设取平均值 11.11
,则剩余金额 66.66
;
以此类推...
该方法也不是完美的,上述是非常理想情况下红包的领取金额,同时每个人获取金额区间相对公平。但是当其中一个人在区间取值接近最小值或者最大值都会对后面的区间造成影响。当取到接近最小值时,后面领取红包金额区间将会变大;反之,则变小。这也是该方法的弊端。
代码实现
# -*- coding: utf-8 -*-
'''
@File: red_packet.py
@Time: 2020/01/29 20:41:36
@Author: 大梦三千秋
@Contact: yiluolion@126.com
'''
# Put the import lib here
import random
def get_random_red_packet(total_amount, quantities):
'''抢红包函数
Args:
total_amount: 红包总金额
quantities: 红包个数
Returns:
返回每人领取红包的金额数
'''
# 用以存储每个人领取的红包金额
amount_list = []
# 抢红包人数
person_num = quantities
# 涉及红包金额可带 2 位小数部分
# 使用先乘 100 计算,再除 100 处理小数点部分
cur_total_amount = total_amount * 100
# 这里采用的是二倍均值法
# 除最后一人,先对前面领取红包金额进行处理
# 最后剩下的金额,即是最后一人的金额
for _ in range(quantities - 1):
amount = random.randint(1, cur_total_amount // person_num * 2)
# 每次减去当前随机金额,用剩余金额进行下次随机获取
cur_total_amount -= amount
person_num -= 1
amount_list.append(amount / 100)
amount_list.append(cur_total_amount / 100)
# print(sum(amount_list))
return amount_list
def main():
amount_list = get_random_red_packet(88.88, 8)
for amount in amount_list:
print('红包金额:{}'.format(amount))
if __name__ == "__main__":
main()
实现效果
红包金额:18.64
红包金额:10.32
红包金额:9.82
红包金额:9.72
红包金额:5.11
红包金额:19.16
红包金额:15.15
红包金额:0.96
延伸
线段切割法
该方法的思路是:把红包总金额当成一条线段,每个人领取红包金额即是该线段拆分的子线段。
当红包数量为 i
时,也就是 i
个人抢红包。对线段进行切割,确定 i - 1
个切割点。
当切割点确定,也就是子线段长度确定。领取红包时只需依次领取子线段对应金额数即可。
以上就是本篇的主要内容
欢迎关注微信公众号《书所集录》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。