1. 程式人生 > >簡單聊聊微信紅包及其演算法

簡單聊聊微信紅包及其演算法

昨天有個小夥伴在微信群裡發一篇文章《如何實現搶紅包演算法》,本著學習的精神(上班太閒) 打開了看看。文章主要是介紹了兩種方法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 元。程式碼如下:
  1. import random  
  2. from __future__ import division  
  3. def average(amount, nums):  
  4. remain_num
     = nums
  5.     for num in range(nums):  
  6.         if remain_num == 1:  
  7. value = amount
  8.         else:  
  9. value = round(random.uniform(0.01, amount/remain_num * 2), 2)  
  10.         amount -value
  11.         remain_num -1
  12.         print('第{}個人搶到{}元紅包,剩餘紅包{}元'.format(num+1, value, amount))  
  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個切割點。程式碼如下:
  1. import random  
  2. def line_cut(total, number):  
  3.     """  
  4.     生成切斷點 (list)  
  5.     :param total:  總數  
  6.     :param number:  人數  
  7.     :return:  
  8.     """  
  9. cut_num = number - 1  
  10. random_list = []  
  11.     for i in range(cut_num):  
  12.         while True:  
  13. random_num = random.randint(1, total)  
  14.             if random_num not in random_list:  
  15.                 random_list.append(random_num)  
  16.                 break  
  17.     return sorted(random_list)  
  18. def amount(total, random_list):  
  19.     """  
  20.     根據切割點分配金額  
  21.     :param total:  
  22.     :param random_list:  
  23.     :return:  
  24.     """  
  25. test_total = 0
  26.     for i in range(len(random_list)+1):  
  27.         try:  
  28. num = random_list[0] if i == 0 else random_list[i+1] - random_list[i]  
  29.         except:  
  30.             try:  
  31. num = total - random_list[i]  
  32.             except:  
  33. num = total - test_total  
  34.         test_total += num  
  35.         print('第{}個人分配金額{}, 剩餘金額{}'.format(i+1, num, total-test_total))  
  36. if __name__ == '__main__':  
  37.     total, number = 100, 10  
  38. random_list = line_cut(total, number)  
  39.     amount(total, random_list)  
瞭解了基本的紅包演算法,好奇心使我開啟google檢視下微信紅包到底使用了哪種方式。有點不相信啊。我要開始我的測試,首先進行小額測試,我發4個紅包,金額是0.05,只有第3,4人才有可能領到0.02,下面是我的驗證還有很多圖就不放了,都是最後一個人是0.02。心有點動搖了啊,,再使用另一個維度測試,我發1元10個包,那第一個人永遠不超過0.2元,下面是我的測試:現在看來是微信採用的是二倍均值法無疑了。那麼問題來了,我們應該先搶還是後搶的?這得看你是否想要大額,因為前面搶的是比較平均的。不可能出現大額。想要大額,後面搶,但是是有風險搶到小額,就是波動較大。(還有特麼可能沒有紅包了)