最全微信红包分配算法!不只是二倍均值那么简单!

一、序言

本文要解决什么问题?

  1. 抢红包的顺序对红包收益有无影响?
  2. 抢红包的顺序对当运气王的概率有无影响?
  3. 红包接龙游戏每次都是先抢好还是后抢好?
  4. 红包接龙游戏运气王当的越多越好还是越少越好?

微信群发红包的红包接龙游戏,抢到手气最佳的人要继续发下去。那么是抢到手气最佳好呢,还是不抢到手气最佳好呢?当然当不当运气王不是我们能决定的,但是抢红包的时机是我们能决定的,所以问题改为:红包接龙游戏每次都是先抢好还是后抢好?为了解决这个问题,我决定用python仿真一下。仿真的前提是知道微信红包随机算法,于是去网上搜索,大多数人仅知道所谓的“二倍平均算法“,即认为微信红包每个红包的值最小为0.01元,最大为当前红包平均值的二倍,如当年最火的毕导的一篇推送
微信红包先抢和后抢差距居然这么大!春节抢红包的大数据分析:https://mp.weixin.qq.com/s/ltsMTmz9krBNswleUyXFwQ
看起来有趣,其实不够全面。最为全面的微信红包随机算法为2016年4月份,时任微信支付后台架构负责人的方乐明发表了一篇文章讲述了微信红包的架构、并发控制、红包算法以及柔性降级方案。该文章在微信公众号的原文链接已被删除,现在最早的为2016.4.12的这篇
《揭秘微信红包:架构、抢红包算法、高并发和降级方案》https://www.cnblogs.com/8hao/p/5383143.html

以防该链接失效失效,下面是多篇转载该文章的链接,

https://blog.csdn.net/code52/article/details/51168854
https://blog.csdn.net/csdn265/article/details/51424138
https://blog.csdn.net/wuliusir/article/details/51496031
https://blog.csdn.net/linkin1989/article/details/81940143
https://mp.weixin.qq.com/s/HVrovIPSHNnZ8au7yetS5g
https://mp.weixin.qq.com/s/H2heF8u8heWSCU-k7M7Gsw
http://www.javashuo.com/article/p-frgrlslr-bs.html
https://www.pianshen.com/article/9719579422/
https://www.shangmayuan.com/a/8ec62fd225f149be9e4606ae.html

二、红包分配算法详述

红包算法原文如下
首先,如果红包只有一个,本轮直接使用全部金额,确保红包发完。
然后,计算出本轮红包最少要领取多少,才能保证红包领完,即本轮下水位;轮最多领取多少,才能保证每个人都领到,即本轮上水位。主要方式如下:
计算本轮红包金额下水位:假设本轮领到最小值1分,那接下来每次都领到200元红包能领完,那下水位为1分;如果不能领完,那按接下来每次都领200元,剩下的本轮应全部领走,是本轮的下水位。
计算本轮红包上水位:假设本轮领200元,剩下的钱还足够接下来每轮领1分钱,那本轮上水位为200元;如果已经不够领,那按接下来每轮领1分,计算本轮的上水位。
为了使红包金额不要太悬殊,使用红包均值调整上水位。如果上水位金额大于两倍红包均值,那么使用两倍红包均值作为上水位。换句话说,每一轮抢到的红包金额,最高为两倍剩下红包的均值。
最后,获取随机数并用上水位取余,如果结果比下水位还小,则直接使用下水位,否则使用随机金额为本轮拆到金额。

三、红包分配算法数学语言描写

将第二章中的算法用数学语言描写出来。
算法输入:当前红包剩余个数n,当前红包剩余金额a
第一步,计算下水位。若a<=200*(n-1)+0.01,则x_down=0.01,否则x_down=a-200*(n-1)
第二步,计算上水位。若a>=200+0.01*(n-1),则x_up=200,否则x_up=a-0.01*(n-1)
第三步,二倍均值法调整。若x_up>a/n2,则x_up=a/n2
第四步,在x_down和x_up中取一个随机数x_rand,包括这两个数,要求精确到小数点两位
第五步,若x_up%x_rand<x_down,则x=x_down,否则x=x_rand
最后,返回x.

四、红包分配算法python代码展示

import random
import numpy as np
import sys
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
def getRedpacket(n,a):#当前红包剩余个数n,当前红包剩余金额a#第一步if a<=200*(n-1)+0.01:x_down=0.01else:x_down=a-200*(n-1)#第二步if a>=200+0.01*(n-1):x_up=200else:x_up=a-0.01*(n-1)x_up=round(x_up,2) #计算机以二进制存储,浮点数算法存在误差,故必须加这步#第三步if x_up>a/n*2:x_up=a/n*2#第四步x_rand=random.uniform(x_down,x_up)x_rand=round(x_rand,2)#第五步if x_up%x_rand<x_down :x=x_downelse:x=x_rand#最后返回此次红包拆出的金额return x

五、抢红包的顺序对红包收益及运气王概率的影响

序言中所提的两个问题,第一个是抢红包的顺序对红包收益有无影响,第二个是抢红包的顺序对当运气王的概率有无影响。其实质是一个问题,毕竟当上运气王就相当于红包收益的最大化。因此这两个问题放在同一节解决,并使用同一段代码。事实上根据网络资料及参考文献,我们可以预见,大数据统计分析的情况一定是运气王在各种次序都有可能,但是越晚抢红包,抢到的金额的方差越大,也就是说更容易出现极端情况,也就是说运气王的概率和倒霉蛋(抢到最少钱数)的概率都比先抢红包的概率高。

数据结构: 红包个数n, 红包金额a, 重复发红包的次数times, 临时存储单次红包分配情况packet [n], 存储某个次序成为运气王的次数king [n], 存储某个次序抢到的总金额数money [n]。

算法思路如下:先输入n,a,times,然后初始化packet[n]=0,king[n]=0, money [n]=0,然后使用for循环n次,循环内部使用getRedpacket函数,并在每次调用后都要更新a和n以及packet[i]和money [i]。最后循环结束后在packet中找到最大值的下标存储到king[ ]中。这样就完整的完成了一次抢红包模拟。将上述流程重复times次,就相当于发了times次红包。代码如下。

def Redpacket(n,a,times):#红包个数n,红包金额a,重复发红包的次数timesif(a>n*200):#错误检验print('出现错误!a_bigger_200n_error')sys.exitpacket = np.zeros(n)#临时存储单次红包分配情况king = np.zeros(n)#存储某个次序成为运气王的次数money = np.zeros(n)#存储某个次序抢到的总金额数for i in range(times):packet = np.zeros(n)#每次开抢之前要初始化packeta_now=an_now=nfor j in range(n_now):packet[j]=getRedpacket(n_now,a_now)a_now=a_now-packet[j]n_now=n_now-1money[j]=money[j]+packet[j]king_i=np.where(packet == np.max(packet))[0][0]#找到运气王的下标,即找到packet数组中最大值的下标king[king_i]=king[king_i]+1    if(king.sum()-20000>1e-2):#错误检验print('出现错误!king_sum_error')sys.exitif(money.sum()-a*times>1e-2):#错误检验print('出现错误!money_sum_error')sys.exitplt.figure(1)plt.title('不同次序抢得的金额数')plt.plot(money)plt.figure(2)plt.title('不同次序当上运气王的次数')plt.plot(king)return king,money

结果如下所示。500块钱分成100个红包,发20000次这样的红包。则金额波动很大,无明显统计规律。运气王则明显存在于最后20个才抢到红包的人。

当5块钱分成10个红包,发20000次这样的红包,结果则变为:后抢红包的金额大,先抢红包的运气王可能性更高。注意,这两者并不矛盾,请读者自行领悟,毕导的文章有详细解读。

若15块钱分成100个红包,发20000次这样的红包,结论又变为:先抢后抢差不多,只有最后一个抢的钱可能更多。运气王的概率则为后抢的大。

最终总结为:抢红包的顺序对红包收益及当运气王的概率有很大影响,但是并不是简单的线性关系。具体关系我们会在第八节分析。

六、红包接龙玩法数学分析

参考文献:https://blog.csdn.net/Mrzhoug/article/details/51367118
群主先发S元红包,随机分成n份(n为群里人数),手气最佳者(即抢得红包最大者)继续发红包,也为S元,n份,下一个手气最佳者继续……从长期来看,每玩一次,每人抢得金额的最大可能性为S/n元(编者注:应为期望值);而每次抢,都有可能成为手气最佳者,可能性为1/n,需要接着发出S元红包。这样看来,每人每次收益的期望值是:S/n-1/n×S=0。长期来看,这样玩法属于零和游戏,大家没输没赢。

七、红包接龙算法详述

本节我们将重点解决序言中提到的第三和第四个问题,即红包接龙游戏每次是先抢好还是后抢好?红包接龙游戏运气王当的越多越好还是越少越好?这两个问题本质也是一样的。我们不能决定能否当运气王,但是能决定自己先抢红包还是后抢红包。所以接下来我们就来探讨红包接龙游戏每次是先抢好还是后抢好。

抢红包的顺序很可能会影响抢到的红包金额以及当运气王的概率,我们要探讨两个问题,一个是当运气王对红包接龙游戏收益的影响一个是抢红包顺序对红包接龙游戏收益的影响,但是无论是哪个问题,每次抢红包都要把按顺序抢红包,而不能是乱序抢红包。不然的话,红包金额是随机的,抢红包顺序也是随机的,那么最后的大数据统计结果也一定是随机的了,没有参考意义。

算法开始。
先筛选无效输入:如果a_packet>n_group*200,则立即返回error。
数据结构: 红包个数n,红包金额a,红包接龙的轮数times,临时存储运气王下标king_now,临时存储单次红包分配情况packet [n],存储某个次序成为运气王的次数king [n],存储某个次序抢到的总金额数money [n]

第一步:先输入n,a,times,然后初始化packet[n]=0,king[n]=0, money [n]=0。刚开始还没有运气王,因此从n中随机选择一个人序号赋值给king_i,发a元钱红包,此时应更新money[king_i]-= a。

第二步:所有人开始抢红包。使用for循环n次,循环内部使用getRedpacket函数,并在每次调用后都要更新a和n以及packet[i]和money [i]。最后循环结束后在packet[ ]中找到最大值的下标,记作king_i,存储到king[ ]中。

第三步:运气王继续发红包。money[king_now]-= a。然后执行第二步。

循环二三步。直至红包接龙结束。

代码如下。

def RedpacketChain(n,a,times):#红包个数n,红包金额a,红包接龙的轮数timesif(a>n*200):#错误检验print('出现错误!a_bigger_200n_error')sys.exitking_i=0,#临时存储运气王下标packet = np.zeros(n)#临时存储单次红包分配情况king = np.zeros(n)#存储某个次序成为运气王的次数money = np.zeros(n)#存储某个次序抢到的总金额数king_i = random.randint(0,n-1)for i in range(times):money[king_i]=money[king_i]-a#运气王发红包,因此其金额减少packet = np.zeros(n)#每次开抢之前要初始化packeta_now=an_now=nfor j in range(n_now):packet[j]=getRedpacket(n_now,a_now)a_now=a_now-packet[j]n_now=n_now-1money[j]=money[j]+packet[j]king_i=np.where(packet == np.max(packet))[0][0]#找到运气王的下标,即找到packet数组中最大值的下标king[king_i]=king[king_i]+1    if(king.sum()-20000>1e-2):#错误检验print('出现错误!king_sum_error')sys.exitif(money.sum()-a*times>1e-2):#错误检验print('出现错误!money_sum_error')sys.exitplt.figure(1)plt.title('不同次序抢得的金额数')plt.plot(money)plt.figure(2)plt.title('不同次序当上运气王的次数')plt.plot(king)return king,money

结果如下所示. 300块钱分成30个红包,进行20000轮次的红包接龙,明显后抢红包的当运气王概率高,则收益明显下降甚至成为了负数。

100块钱分成10个红包,进行20000轮次的红包接龙,结论不变,后抢红包的当运气王概率高,收益会下降成为了负数。

八、红包总额、红包个数与运气王的真正关系!

我想探寻红包总额、红包个数与运气王的真正关系!目前的思路就是画一个三维图像,x轴为红包总额,y轴为红包个数,纵轴为拿到运气王的次序,这样的3D图像就能形象展现出这三者的关系,但是时间复杂度将很大!比如红包个数,从2个到100个,间隔1,则有99个取值,红包总金额,从1元到1000元,间隔1,则有1000个取值,在每个交叉点执行一次Redpacket()函数,该函数内部本身又有一个times次循环和红包个数n嵌套的双重循环,若times=1000,则时间复杂度为10010001000*100=10的10次方!相关绘图代码我放在下面,等我有空或者其他感兴趣的读者自己运行一下。

def Redpacket_king(n,a,times=10000):#红包个数n,红包金额a,重复发红包的次数times#本函数由Redpacket函数改编,仅用于返回获得运气王次数最多的次序数if(a>n*200):#错误检验print('出现错误!a_bigger_200n_error')sys.exitpacket = np.zeros(n)#临时存储单次红包分配情况king = np.zeros(n)#存储某个次序成为运气王的次数money = np.zeros(n)#存储某个次序抢到的总金额数for i in range(times):packet = np.zeros(n)#每次开抢之前要初始化packeta_now=an_now=nfor j in range(n_now):packet[j]=getRedpacket(n_now,a_now)a_now=a_now-packet[j]n_now=n_now-1money[j]=money[j]+packet[j]king_i=np.where(packet == np.max(packet))[0][0]#找到运气王的下标,即找到packet数组中最大值的下标king[king_i]=king[king_i]+1    if(king.sum()-20000>1e-2):#错误检验print('出现错误!king_sum_error')sys.exitif(money.sum()-a*times>1e-2):#错误检验print('出现错误!money_sum_error')sys.exitking_a=np.where(king == np.max(king))[0][0]return king_a
#本代码时间复杂度很大
n = np.arange(2, 100, 1)#红包个数,从2个到100个,间隔1
a = np.arange(1, 1000, 1)#红包总金额,从1元到1000元,间隔1
x,y = np.meshgrid(n, a)
king=np.zeros(shape=x.shape)
for i in range(1, 1000, 1):for j in range(2, 100, 1):if(i>200*j):continueprint("i:",i," j:",j)king[i-1][j-2] = Redpacket_king(j,i)
fig = plt.figure()
ax = Axes3D(fig)
surf=ax.plot_surface(x,y,king, rstride=1, cstride=1, cmap=cm.viridis)
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()

九、版权声明

仅需标注出处即可随意对本文进行转载、参考或使用。

最全微信红包分配算法,不只是二倍均值那么简单相关推荐

  1. python分配红包程序_Python版微信红包分配算法

    Python版微信红包分配算法 发布于 2015-05-08 10:54:23 | 151 次阅读 | 评论: 0 | 来源: 网友投递 Python编程语言Python 是一种面向对象.解释型计算机 ...

  2. java实现红包要多少钱_java实现微信红包分配算法

    本文由我司收集整编,推荐下载,如有疑问,请与我司联系 java 实现微信红包分配算法 2017/03/25 0 红包算法分析有人认为,抢红包的额度是从 0.01 到剩余平均值 *N(N 是一个系数,决 ...

  3. 微信红包分配算法原理

    微信红包分配算法原理 春节这几天,大家在红包群里抢了不少红包了吧,有没有试过总金额上百的红包抢到手之后只有几毛钱?为什么有些人能抢到总金额的一半甚至更多?下面,我来给大家讲讲微信红包分配的算法原理. ...

  4. java实现红包要多少钱_java实现微信红包分配算法(示例代码)

    红包算法分析 有人认为,抢红包的额度是从0.01到剩余平均值*N(N是一个系数,决定最大的红包值)之间,比如一共发了10块钱,发了10个红包:第一个人可以拿到(0.01~1*N)之间的一个红包值,当然 ...

  5. java红包金额随机数算法_实时随机数算法(微信红包分配算法)

    微信红包算法在知乎上面有个专题讨论,其实红包的发放的随机算法,有两种作法:java 一.预生产: 算法 无外乎是在发红包的时候,随机去把金额生成到某个容器当中,而后要用的时候,一个一个的POP:微信 ...

  6. 前端实现红包雨功能_最全解密微信红包随机算法(含代码实现)

    code小生 一个专注大前端领域的技术平台公众号回复 Android加入安卓技术群 "  1.引言 这个系列文章已经整理了10篇,但都没有涉及到具体的红包算法实现,主要有以下两方面原因.一方 ...

  7. 最全解密微信红包随机算法(含代码实现)

    code小生 一个专注大前端领域的技术平台 公众号回复Android加入安卓技术群 " 本文内容编写时,参考了网上的资料,详见"参考资料"部分,感谢分享者..本文已同步发 ...

  8. php 红包算法教程,php仿微信红包分配算法的实现方法

    php仿微信红包分配算法的实现方法 本文实例讲述了php仿微信红包分配算法的实现方法.分享给大家供大家参考,具体如下: /** * 红包分配:把一定金额随机分配给指定人数 * * @param int ...

  9. 红包的分配算法php,php仿微信红包分配算法的实现方法,红包算法

    php仿微信红包分配算法的实现方法,红包算法 本文实例讲述了php仿微信红包分配算法的实现方法.分享给大家供大家参考,具体如下: /** * 红包分配:把一定金额随机分配给指定人数 * * @para ...

最新文章

  1. MySQL 四种事务隔离级别详解及对比--转
  2. 服务器维护菜单,Romley平台BIOS常用操作
  3. 根据状态转移写状态机-三段式
  4. PLSQL中INDEX BY TABLE 的 prior 和 next 操作学习
  5. Java中array、List、Set互相转换
  6. arch linux简体中文,User-mode Linux (简体中文)
  7. 【英语学习】【WOTD】palimpsest 释义/词源/示例
  8. C语言-Ubuntu下GDB与GCC的安装与使用
  9. JSP servlet的配置与使用
  10. vue-router的两种模式
  11. clousx6机器人卡密_手机x6机器人词库编程-clousx6词库助手免费版v8.0 安卓最新版-2265安卓网...
  12. windows下yafu的下载及其安装
  13. 科海思除镍树脂CH-90Na
  14. 汽车电线束双绞线技术参数设定
  15. 【资损】系统迭代过程中的兼容性设计
  16. WEBRTC中VAD算法及思想的数学解析
  17. 计算机分辨率无法调整,电脑分辨率调不了怎么办?电脑分辨率不能调的解决方法...
  18. mysql mdf ldf_mdf和ldf是什么文件
  19. 深入理解安卓异步任务AsyncTask
  20. Centos 7.4 防火墙关闭命令

热门文章

  1. Flink 生产环境配置建议
  2. 考研高等数学公式总结(三)
  3. windows server 2016 活动目录部署系列(十一)AD域控上安装证书服务器
  4. MongoDB学习记录10-分片-副本集(mongodb3.2版本以前)
  5. 去中心化自治组织DAO简要介绍
  6. 抽取modelnet40_ply_hdf5_2048数据集的子类集制作h5点云
  7. matlab实现拉依达准则,拉依达准则matalb程序
  8. vue渲染大量数据如何优化_大数据量场景下的Vue性能优化
  9. windows10专业版 docker desktop 安装失败
  10. 标签打印机打印亚马逊外箱FBA标签