昨天有个小伙伴在微信群里发一篇文章
《如何实现抢红包算法》,本着学习的精神(上班太闲) 打开了看看。
文章主要是介绍了两种方法
1.二倍均值法
剩余红包金额为M,剩余人生为N,那么有如下的公式:
每次抢到的金额 = 随机区间 (0, M/N *2)
举个例子:
假设有10个人,红包金额为10元,
第1个人抢到的金额范围为 (0, 10/10 * 2),平均为1 元。
第2个人抢到的金额范围为 (0, 9/9 * 2),平均为1 元。
...
第10个人抢到的金额范围为 (0, 1/1 * 2),平均为1 元。
代码如下:
- import random
- from __future__ import division
- def average(amount, nums):
- remain_num = nums
- for num in range(nums):
- if remain_num == 1:
- value = amount
- else:
- value = round(random.uniform(0.01, amount/remain_num * 2), 2)
- amount -= value
- remain_num -= 1
- print('第{}个人抢到{}元红包,剩余红包{}元'.format(num+1, value, amount))
- >>> average(10, 10)
- 第1个人抢到0.58元红包,剩余红包9.42元
- 第2个人抢到1.62元红包,剩余红包7.8元
- 第3个人抢到0.55元红包,剩余红包7.25元
- 第4个人抢到0.86元红包,剩余红包6.39元
- 第5个人抢到1.7元红包,剩余红包4.69元
- 第6个人抢到1.51元红包,剩余红包3.18元
- 第7个人抢到0.32元红包,剩余红包2.86元
- 第8个人抢到1.06元红包,剩余红包1.8元
- 第9个人抢到1.43元红包,剩余红包0.37元
- 第10个人抢到0.37元红包,剩余红包0.0元
- >>> average(10, 10)
- 第1个人抢到0.35元红包,剩余红包9.65元
- 第2个人抢到0.35元红包,剩余红包9.3元
- 第3个人抢到1.58元红包,剩余红包7.72元
- 第4个人抢到0.17元红包,剩余红包7.55元
- 第5个人抢到2.48元红包,剩余红包5.07元
- 第6个人抢到0.79元红包,剩余红包4.28元
- 第7个人抢到0.99元红包,剩余红包3.29元
- 第8个人抢到0.79元红包,剩余红包2.5元
- 第9个人抢到0.33元红包,剩余红包2.17元
- 第10个人抢到2.17元红包,剩余红包0.0元
二、线性分割法
我们可以把红包总金额想象成一条很长的线段,而每个人抢到的金额,则是这条主线段所拆分出的若干子线段。
如何确定每一条子线段的长度呢?由“切割点”来决定。当N个人一起抢红包的时候,就需要确定N-1个切割点。
代码如下:
- import random
- def line_cut(total, number):
- """
- 生成切断点 (list)
- :param total: 总数
- :param number: 人数
- :return:
- """
- cut_num = number - 1
- random_list = []
- for i in range(cut_num):
- while True:
- random_num = random.randint(1, total)
- if random_num not in random_list:
- random_list.append(random_num)
- break
- return sorted(random_list)
- def amount(total, random_list):
- """
- 根据切割点分配金额
- :param total:
- :param random_list:
- :return:
- """
- test_total = 0
- for i in range(len(random_list)+1):
- try:
- num = random_list[0] if i == 0 else random_list[i+1] - random_list[i]
- except:
- try:
- num = total - random_list[i]
- except:
- num = total - test_total
- test_total += num
- print('第{}个人分配金额{}, 剩余金额{}'.format(i+1, num, total-test_total))
- if __name__ == '__main__':
- total, number = 100, 10
- random_list = line_cut(total, number)
- amount(total, random_list)
了解了基本的红包算法,好奇心使我打开google查看下微信红包到底使用了哪种方式。
有点不相信啊。我要开始我的测试,首先进行小额测试,我发4个红包,金额是0.05,只有第3,4人才有可能领到0.02,
下面是我的验证
还有很多图就不放了,都是最后一个人是0.02。心有点动摇了啊,,再使用另一个维度测试,我发1元10个包,
那第一个人永远不超过0.2元,下面是我的测试:
现在看来是微信采用的是二倍均值法无疑了。
那么问题来了,我们应该先抢还是后抢的?
这得看你是否想要大额,因为前面抢的是比较平均的。不可能出现大额。
想要大额,后面抢,但是是有风险抢到小额,就是波动较大。(还有特么可能没有红包了)