简单聊聊微信红包及其算法

昨天有个小伙伴在微信群里发一篇文章 《如何实现抢红包算法》,本着学习的精神(上班太闲) 打开了看看。

文章主要是介绍了两种方法

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 元。

代码如下:

[html]  view plain  copy
  1. import random  
  2. from __future__ import division  
  3.   
  4. def average(amount, nums):  
  5.     remain_num = nums  
  6.     for num in range(nums):  
  7.         if remain_num == 1:  
  8.             value = amount  
  9.         else:  
  10.             value = round(random.uniform(0.01, amount/remain_num * 2), 2)  
  11.         amount -value  
  12.         remain_num -1  
  13.         print('第{}个人抢到{}元红包,剩余红包{}元'.format(num+1, value, amount))  
[html]  view plain  copy
  1. >>> average(10, 10)  
  2. 第1个人抢到0.58元红包,剩余红包9.42元  
  3. 第2个人抢到1.62元红包,剩余红包7.8元  
  4. 第3个人抢到0.55元红包,剩余红包7.25元  
  5. 第4个人抢到0.86元红包,剩余红包6.39元  
  6. 第5个人抢到1.7元红包,剩余红包4.69元  
  7. 第6个人抢到1.51元红包,剩余红包3.18元  
  8. 第7个人抢到0.32元红包,剩余红包2.86元  
  9. 第8个人抢到1.06元红包,剩余红包1.8元  
  10. 第9个人抢到1.43元红包,剩余红包0.37元  
  11. 第10个人抢到0.37元红包,剩余红包0.0元  
  12. >>> average(10, 10)  
  13. 第1个人抢到0.35元红包,剩余红包9.65元  
  14. 第2个人抢到0.35元红包,剩余红包9.3元  
  15. 第3个人抢到1.58元红包,剩余红包7.72元  
  16. 第4个人抢到0.17元红包,剩余红包7.55元  
  17. 第5个人抢到2.48元红包,剩余红包5.07元  
  18. 第6个人抢到0.79元红包,剩余红包4.28元  
  19. 第7个人抢到0.99元红包,剩余红包3.29元  
  20. 第8个人抢到0.79元红包,剩余红包2.5元  
  21. 第9个人抢到0.33元红包,剩余红包2.17元  
  22. 第10个人抢到2.17元红包,剩余红包0.0元  
二、线性分割法

我们可以把红包总金额想象成一条很长的线段,而每个人抢到的金额,则是这条主线段所拆分出的若干子线段。


如何确定每一条子线段的长度呢?由“切割点”来决定。当N个人一起抢红包的时候,就需要确定N-1个切割点。

代码如下:

[html]  view plain  copy
  1. import random  
  2.   
  3.   
  4. def line_cut(total, number):  
  5.     """  
  6.     生成切断点 (list)  
  7.     :param total:  总数  
  8.     :param number:  人数  
  9.     :return:  
  10.     """  
  11.     cut_num = number - 1  
  12.     random_list = []  
  13.     for i in range(cut_num):  
  14.         while True:  
  15.             random_num = random.randint(1, total)  
  16.             if random_num not in random_list:  
  17.                 random_list.append(random_num)  
  18.                 break  
  19.     return sorted(random_list)  
  20.   
  21. def amount(total, random_list):  
  22.     """  
  23.     根据切割点分配金额  
  24.     :param total:  
  25.     :param random_list:  
  26.     :return:  
  27.     """  
  28.     test_total = 0  
  29.     for i in range(len(random_list)+1):  
  30.         try:  
  31.             num = random_list[0] if i == 0 else random_list[i+1] - random_list[i]  
  32.         except:  
  33.             try:  
  34.                 num = total - random_list[i]  
  35.             except:  
  36.                 num = total - test_total  
  37.         test_total += num  
  38.         print('第{}个人分配金额{}, 剩余金额{}'.format(i+1, num, total-test_total))  
  39.   
  40. if __name__ == '__main__':  
  41.     total, number = 100, 10  
  42.     random_list = line_cut(total, number)  
  43.     amount(total, random_list)  
了解了基本的红包算法,好奇心使我打开google查看下微信红包到底使用了哪种方式。

有点不相信啊。我要开始我的测试,首先进行小额测试,我发4个红包,金额是0.05,只有第3,4人才有可能领到0.02,

下面是我的验证


还有很多图就不放了,都是最后一个人是0.02。心有点动摇了啊,,再使用另一个维度测试,我发1元10个包,

那第一个人永远不超过0.2元,下面是我的测试:


现在看来是微信采用的是二倍均值法无疑了。

那么问题来了,我们应该先抢还是后抢的?

这得看你是否想要大额,因为前面抢的是比较平均的。不可能出现大额。

想要大额,后面抢,但是是有风险抢到小额,就是波动较大。(还有特么可能没有红包了) 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值