抽奖活动中,如何利用一个系数调节中奖的频率

抽奖活动中,如何利用一个系数调节中奖的频率_第1张图片

活动:在女神节当天,用户点击活动页面的抽奖按钮,可随机获得一张优惠券。

背景:由于经费限制,最多发放200张。并且要求不能集中到一个时间段发放。中奖时间平均要分布在上午09点-下午07点。 


每次用户抽奖,系统需要一个算法,返回一个布尔值(是否中奖)。这个算法要保证两点:

  1. 十个小时下来,中奖时间分布要均匀;

  2. 中奖人数不能超过200


这个算法的主要难点在于:设计程序时,无法预知这一天将会有多少人参加活动,甚至他们将会在什么时间参加。如果可以预知这些,那么根据参加活动的总人数,很容易计算出来哪些人是中奖的,然后当这些人抽奖的时候,算法返回一个true就行了。但事实是我们都没有预知未来的能力。


为了解决这个问题,我们首先假定一个浮点类型的系数k作为每秒参加活动的人数,并将其存放在mongo中。活动开始后,再根据实时的热度随时调整到接近真实的数值(估算值)。我们暂且称这个系数为活动的“热度系数”。

k >= 1 :说明每秒有k个人访问

k < 1 :说明每隔1/k秒,有1个人访问 


上面介绍过,活动有效期是10个小时。那么在活动期间,每个用户抽奖时,我们都可以得到一个活动剩余的时间t(单位:秒)。

所以:

剩余秒数*每秒参加活动人数=剩余参加活动人数(C)

t * k = C


因为最多发放200张,所以我们必须有一个针对剩余优惠券的计数器,每次发出一张就减1。计数器的数字永远表示剩余多少张优惠券(M)可以发放。


所以当一个人来抽奖时,他中奖的概率就是:

剩余优惠券张数M / 剩余参加活动人数C

即:剩余优惠券张数M  / (剩余秒数t * 每秒参加活动人数k)

换成公式的话,这个用户中奖的概率就是:M / ( t * k )


有了中奖的概率,我们可以在1至分母( t * k )之间,随机一个数字,如果这个数字小于等于分子(M),说明中奖了。


举个栗子:当一个用户抽奖时,假设:

  • 剩余140张优惠券(M=140);

  • 活动剩余4小时10分钟,换算成秒是15000秒(s=15000);

  • 当前活动热度系数为0.5(k=0.5,代表目前每2秒有一个人参加活动)。

换言之,这个用户抽奖那一刻,还有140张券可以被抽中,但是他后面还有7500(15000 * 0.5)个用户等待抽奖,所以他的抽中的概率就是140/7500。模拟这个概率很简单,我们从 1 ~7500 中随机一个数字,如果得出一个小于等于140的数字,说明此用户中奖了,反之没有中奖。


这样一来,活动开始后,我们需要做的事情就是:根据实际情况,随时调整活动的热度系数(k)。热度系数变了,中奖的概率也就变了。


这样貌似大功告成了,但还有一个问题悬而未解:虽然这个算法尽量保证了中奖概率的分散性,但仍然无法完全保证中奖的时间可以平均分布在09点~19点之间。


为此我将200张优惠券分成10组,每组20张,正好对应这10个小时。然后把上面的算法应用在每个小时范围内。调整以下3处代码:

  1. 获取剩余秒数时,取当前小时剩余的秒数;

  2. 剩余张数计数器拆分成10个(20张/个),分别对应活动的10个小时;

  3. 获取剩余优惠券张数时,取当前小时剩余的优惠券;


换句话说,我将活动按小时细分成10个时间段,每个时间段平均发放20张,整体一天活动下来,保证了中奖时间的分散性。


每周一篇技术文章,关注微信订阅号:

抽奖活动中,如何利用一个系数调节中奖的频率_第2张图片


你可能感兴趣的:(抽奖活动中,如何利用一个系数调节中奖的频率)