红包分配算法的再探究

红包分配算法的再探究

一、 理论分析并精简红包分配算法

根据上一篇文章所述的红包分配算法,我们可以将前三步写为以下分段函数:红包分配算法的再探究_第1张图片
此时我们可以发现第二步和第三步是可以合并的,因此我们暂时可以第二三步合并写为如下分段函数:
在这里插入图片描述
我们整理一下,将n作为已知量,a作为自变量,得到如下分段函数:
在这里插入图片描述
此时我们可以发现,决定x_up分段函数的最终形态的有三个关键点,第一个是100n,第二个是199.99+0.01n,第三个是0.01n(n-1)/n-2,再加上决定了x_down的关键点200n-199.99,我们只需要确定这四个点的大小关系就可以最终确定x_down和x_up分段函数的最终形态了。使用下述代码可以确定。

n=np.arange(3, 100, 1)
x_down=200*n-199.99
x_up1=100*n
x_up2=0.01*n+199.99
x_up3=0.01*(n-1)*n/(n-2)
plt.plot(x_down,label ="x_down")
plt.plot(x_up1,label ="x_up1")
plt.plot(x_up2,label ="x_up2")
plt.plot(x_up3,label ="x_up3")
plt.legend()
plt.show()

红包分配算法的再探究_第2张图片
根据上图我们可以清楚的看出200n-199.99>100n>0.01n+199.99>0.01(n-1)*n/(n-2),要注意n的取值范围为大于等于3。事实上我们不用代码,只用数学也可以证明上述不等式串的成立。因此我们最终确定x_up分段函数的形态为:
在这里插入图片描述
此外,我们还可以数学证明大多数情况下,x_up的函数值是大于x_down的函数值的,在此不再赘述。

二、 控制变量法探究红包个数,红包总金额与抢到金额的关系

下面考虑固定变量法研究getRedpacket(n,a),即固定红包个数n,逐渐增加红包总金额a,代码如下。

#下面考虑固定变量法研究getRedpacket(n,a)
#固定红包个数n,逐渐增加红包总金额a
n=5#固定红包个数
a=1200#红包总金额,从1元开始逐渐增加红包总金额a,间隔1
times=200 #getRedpacket()函数具有随机性,因此要重复多次取平均值

money=np.zeros(a+1)
for i in range(1, a+1, 1):
    for j in range(times):
        #print("i:",i," j:",j)
        money[i] = money[i]+getRedpacket(n,i)
        
    money[i]=money[i]*n/i/times
plt.title('固定红包个数,红包总金额与抢到金额的关系折线图(已归一化)')
plt.xlabel('红包总金额')
plt.ylabel('抢到的金额')
plt.plot(money)
plt.show()

红包分配算法的再探究_第3张图片
此时我们可以发现,在固定红包个数为5个的前提下,红包总金额从1元开始增加到1200元的过程中,抢到的金额并不是稳定的,在1元到500元左右的时候,抢到金额经过归一化稳定在1.0附近,也就是说符合随机情况,但是500元之后开始下降,到900元之后又开始上升,这是怎么回事呢?这就应该看本文第一节所说的x_up和x_down的转折点了。当n=5的时候,x_down分段函数的分界点为800.01,x_up分段函数的分界点为0.07和500,完美符合本图。也就是说,如果你发一个含有5个红包的微信红包,那么在500元之内都是符合随机情况,但是在500到800之间,你抢到的金额反而会低于平均值,但是在800之后又会骤增。

我们将红包个数固定为20,也可以发现这种规律。代码如下。

#下面考虑固定变量法研究getRedpacket(n,a)
#固定红包个数n,逐渐增加红包总金额a
n=20#固定红包个数
a=4100#红包总金额,从1元开始逐渐增加红包总金额a,间隔1
times=200 #getRedpacket()函数具有随机性,因此要重复多次取平均值

money=np.zeros(a+1)
for i in range(1, a+1, 1):
    for j in range(times):
        #print("i:",i," j:",j)
        money[i] = money[i]+getRedpacket(n,i)
        
    money[i]=money[i]*n/i/times
plt.title('固定红包个数,红包总金额与抢到金额的关系折线图(已归一化)')
plt.xlabel('红包总金额')
plt.ylabel('抢到的金额')
plt.plot(money)
plt.show()

含有20个红包的微信红包,总金额在2000之前,你抢到金额的期望值都是符合随机的,但是2000到3800之间期望会下降,3800之后又会上升。也是符合x_down和x_up分段函数的。

接下来我们考虑固定红包总金额a,逐渐增加红包个数n的控制变量法来研究红包分配算法。理论分析有些困难,比如x_up的一个分界点,0.01n(n-1)/n-2=a中解出n的取值,就是解如下的二次方程:0.01n*n-(0.01+a)n+2a=0,结果很复杂,而在实际情况中也能发现,比如我们将红包总金额a固定为10,红包个数逐步增加。代码如下。

#固定红包总金额a,逐渐增加红包个数n
n=100#红包个数,从3个开始逐渐增加红包个数至n,间隔1
a=10#固定红包总金额为a
times=500 #getRedpacket()函数具有随机性,因此要重复多次取平均值

money=np.zeros(n+1)
for i in range(3, n+1, 1):
    for j in range(times):
        #print("i:",i," j:",j)
        money[i] = money[i]+getRedpacket(i,a)
    money[i]=money[i]*i/a/times
plt.title('固定红包总金额,红包个数与抢到金额的关系折线图(已归一化)')
plt.xlabel('红包个数')
plt.ylabel('抢到的金额')
plt.plot(money)
plt.show()

红包分配算法的再探究_第4张图片
10块钱的红包,分成3个到100个发,似乎都是符合随机的,但是我们把个数增加到1000,如下图所示。情况变得很复杂了。感兴趣的朋友可以自己尝试分析以下为什么会出现下面的情况。
红包分配算法的再探究_第5张图片
同样,我们固定红包总金额为100,红包个数在3-1000都是较为平缓,如下图所示。
红包分配算法的再探究_第6张图片
但是当个数增加到10000,就会出现下图的复杂规律现象。在此本人不做探究。
红包分配算法的再探究_第7张图片

三、 画出红包总金额、红包个数与抢到金额的3D图像

第一节我们使用数学分析探讨了红包总金额、红包个数与抢到金额的关系,第二节我们使用控制变量法讨论完了红包总金额、红包个数与抢到金额的关系,接下来第三节我们能否通过绘制3D图像直观的展现出红包总金额、红包个数与抢到金额的关系呢?答案是不行。我们先绘制红包个数2到100,红包总金额1元到1000元的3D图像。代码如下。

#本代码时间复杂度如何?
n=100#红包个数,从2个到100个,间隔1
a=1000#红包总金额,从1元到1000元,间隔1
times=200 #getRedpacket()函数具有随机性,因此要重复多次取平均值
n_1 = np.arange(2, n, 1)#红包个数,从2个到100个,间隔1
a_1 = np.arange(1, a, 1)#红包总金额,从1元到1000元,间隔1
x,y = np.meshgrid(n_1, a_1)
money=np.zeros(shape=x.shape)
for i in range(1, a, 1):
    for j in range(2, n, 1):
        #print("i:",i," j:",j)
        for k in range(times):
            money[i-1][j-2] = money[i-1][j-2]+getRedpacket(j,i)
        money[i-1][j-2]=money[i-1][j-2]*j/i/times
fig = plt.figure()
ax = Axes3D(fig)
surf=ax.plot_surface(x,y,money, rstride=1, cstride=1, cmap=cm.viridis)
ax.set_xlabel('红包个数')
ax.set_ylabel('红包总金额')
ax.set_zlabel('抢到的金额')
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()

红包分配算法的再探究_第8张图片
图中我们可以看出,一般情况下抢到的金额是符合随机分配的,但是红包个数太少而红包总金额过多,图像就会出现高峰,即抢到的金额就会暴增;而红包个数太多或红包总金额过少,图像就会出现低谷,即抢到的金额就会骤减。但是无法直观的看出具体分界点。下图为红包个数从2-10个,红包总金额取值范围为1-1000元,也能得出上面的结论。
红包分配算法的再探究_第9张图片
红包个数从2个到5个,红包总金额从1元到1000元,结果图如下。
红包分配算法的再探究_第10张图片
红包个数从2个到10个,红包总金额从1元到100元,结果图如下。
红包分配算法的再探究_第11张图片

四、 总结

写完了两篇探究红包分配算法的文章,发现一个小小的红包分配算法竟然有如此多可以研究的点。总的来说,我们研究了以下问题。在第一篇文章中主要探究了抢红包次序与当上运气王概率及抢到金额的关系;第二篇文章即本篇文章,主要探究了红包总金额、红包个数与抢到金额这三者之间的关系。如此说来我有点本末倒置了,事实上最根本的红包分配算法应该不考虑抢红包次序。每抢一次红包只是对红包分配算法的重复调用而已。总的来说,应该先探究最基本的只考虑单次的红包分配算法,再探究和抢红包次序有关的红包分配算法,最后探究红包接龙玩法。

五、 展望

遗憾的是,这两篇文章我也只是出于自己的好奇而随便探究一下,并未得出什么有用的结论。也不能给大家提供什么实用的抢红包策略。无论是只考虑单次的红包分配算法,还是和抢红包次序有关的红包分配算法,还是最后的红包接龙玩法,都浅尝辄止。不过也没关系,毕竟强如清华博士毕导也没有我想的周全。

你可能感兴趣的