本篇内容为抢随机红包模拟算法,仅供参考。python
本篇使用的是二倍均值法,在此以前,先大概讲下普通随机法。算法
该方法的原理是:每次都以 [最小值,剩余金额值]
之间进行随机取值。微信
假设红包金额为 88.88
,红包数量为 8
个,那么第一我的领取金额将从 [0.01, 88.88]
之间进行取值,假设取值为 20.20
,那么剩余的金额为 68.68
。app
第二个领取金额将从 [0,01, 68.68]
之间进行取值,以此类推...dom
这里能够明显看出此方法的弊端,前面领取红包的金额区间更大,也就更容易获取更大的红包金额。下面看二倍均值法的原理。函数
方法实现的原理是:每次以 [最小值,红包剩余金额 / 人数 * 2]
的区间进行取值。code
假设红包金额为 88.88
,红包数量为 8
个,理想状况下,方法的实现效果:orm
第一我的领取红包金额区间为 [0.01, 88.88 / 8 * 2]
,便是 [0.01, 22.22]
之间随机获取金额数。假设取平均值 11.11
,则剩余金额 77.77
;utf-8
第二我的领取红包金额区间为 [0.01, 77.77 / 7 * 2]
,便是 [0.01, 22.22]
之间随机获取金额数。假设取平均值 11.11
,则剩余金额 66.66
;get
以此类推...
该方法也不是完美的,上述是很是理想状况下红包的领取金额,同时每一个人获取金额区间相对公平。可是当其中一我的在区间取值接近最小值或者最大值都会对后面的区间形成影响。当取到接近最小值时,后面领取红包金额区间将会变大;反之,则变小。这也是该方法的弊端。
# -*- 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
个切割点。
当切割点肯定,也就是子线段长度肯定。领取红包时只需依次领取子线段对应金额数便可。
以上就是本篇的主要内容
欢迎关注微信公众号《书所集录》