sponsored links

為啥春節搶紅包總不是手氣最佳?看完微信搶紅包演算法你就明白了

為啥春節搶紅包總不是手氣最佳?看完微信搶紅包演算法你就明白了

PK創意鬧新春,我正在參加「春節創意投稿大賽」,詳情請看:春節創意投稿大賽”

前言

春節必不可少的活動就是搶紅包啦,從以前的紙質紅包到現在網際網路紅包(以微信紅包為首),今天我們就來分析一下搶紅包的演算法,其中有一些是微信紅包的演算法,看完你就知道手氣最佳是如何產生的啦!

為啥春節搶紅包總不是手氣最佳?看完微信搶紅包演算法你就明白了

演算法一:剩餘金額隨機法

演算法一是不推薦使用的,演算法一全稱叫剩餘金額隨機法,聽名字就知道這個方法是將剩餘的金額進行隨機分配,我們先來看程式碼。

// 分配紅包的演算法
private static void testPocket(BigDecimal amount, BigDecimal min, BigDecimal num) {
BigDecimal remain = amount.subtract(min.multiply(num));
final Random random = new Random();
final BigDecimal hundred = new BigDecimal("100");
BigDecimal sum = BigDecimal.ZERO;
BigDecimal redpeck ;
for (int i = 0; i < num.intValue(); i++) {
    final int nextInt = random.nextInt(100);
    if (i == num.intValue() - 1) {
        redpeck = remain;
    } else {
        redpeck = new BigDecimal(nextInt).multiply(remain).divide(hundred, 2, RoundingMode.FLOOR);
    }
    if (remain.compareTo(redpeck) > 0) {
        remain = remain.subtract(redpeck);
    } else {
        remain = BigDecimal.ZERO;
    }
    sum = sum.add(min.add(redpeck));
    System.out.println("第" + (i + 1) + "個人搶到紅包金額為:" + min.add(redpeck).setScale(2, BigDecimal.ROUND_HALF_UP));
}
System.out.println("紅包總額:" + sum.setScale(2, BigDecimal.ROUND_HALF_UP));
}
// 測試程式碼
public static void main(String[] args) {
    BigDecimal amount = new BigDecimal(100).setScale(2, BigDecimal.ROUND_HALF_UP);
    BigDecimal min = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
    BigDecimal num = new BigDecimal(10).setScale(2, BigDecimal.ROUND_HALF_UP);
    testPocket2(amount,min,num);
}
複製程式碼

我們可以看到,這個方法是有很明顯的缺陷的,就是一開始領到紅包的人獲取的金額可能是最大的,後面領取的金額就逐漸變小了,因為他是從剩餘額金額進行隨機的。很顯然微信是肯定不會使用這種方法作為紅包瓜分演算法,不然每次一有紅包,馬上領取就有可能獲取手氣最佳,但是明顯不是。

演算法二:整體隨機法

整體金額隨機法的公式:紅包總額 * 隨機數/隨機數總和,這個方法的核心是使用一個隨機數作為紅包瓜分的標準,這個隨機數是透過Random類隨機產生的。他的隨機性就比較大了,看起來好像是和我們平時搶紅包差不多,但是微信紅包也不是採用這種方法,因為這種的隨機性太大了,不是很公平。


private static void testPocket2(BigDecimal amount,BigDecimal min ,BigDecimal num){
    final Random random = new Random();
    final int[] rand = new int[num.intValue()];
    BigDecimal sum1 = BigDecimal.ZERO;
    BigDecimal redpeck ;
    int sum = 0;
    for (int i = 0; i < num.intValue(); i++) {
        rand[i] = random.nextInt(100);
        sum += rand[i];
    }
    final BigDecimal bigDecimal = new BigDecimal(sum);
    BigDecimal remain = amount.subtract(min.multiply(num));
    for (int i = 0; i < rand.length; i++) {
        if(i == num.intValue() -1){
            redpeck = remain;
        }else{
            redpeck = remain.multiply(new BigDecimal(rand[i])).divide(bigDecimal,2,RoundingMode.FLOOR);
        }
        if(remain.compareTo(redpeck) > 0){
            remain = remain.subtract(redpeck);
        }else{
            remain = BigDecimal.ZERO;
        }
        sum1= sum1.add(min.add(redpeck)).setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println("第"+(i+1)+"個人搶到紅包金額為:"+min.add(redpeck).setScale(2, BigDecimal.ROUND_HALF_UP));
    }

    System.out.println("紅包總額:"+sum1);
}

// 測試程式碼
public static void main(String[] args) {
    BigDecimal amount = new BigDecimal(100).setScale(2, BigDecimal.ROUND_HALF_UP);
    BigDecimal min = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
    BigDecimal num = new BigDecimal(10).setScale(2, BigDecimal.ROUND_HALF_UP);
    testPocket2(amount,min,num);
}

複製程式碼

他的隨機性可謂是很高,也不是最佳選擇。

演算法三:割線法

割線法指的是把紅包總金額想象成一條很長的線段,而每個人搶到的金額,則是這條主線段所拆分出的若干子線段,當所有切割點確定以後,子線段的長度也隨之確定。這樣每個人來搶紅包的時候,只需要順次領取與子線段長度等價的紅包金額即可。

為啥春節搶紅包總不是手氣最佳?看完微信搶紅包演算法你就明白了

private static void testPocket3(BigDecimal amount, BigDecimal min, BigDecimal num) {
    final Random random = new Random();
    final int[] rand = new int[num.intValue()];
    BigDecimal sum1 = BigDecimal.ZERO;
    BigDecimal redpeck;
    int sum = 0;
    for (int i = 0; i < num.intValue(); i++) {
        rand[i] = random.nextInt(100);
        sum += rand[i];
    }
    final BigDecimal bigDecimal = new BigDecimal(sum);
    BigDecimal remain = amount.subtract(min.multiply(num));
    for (int i = 0; i < rand.length; i++) {
        if (i == num.intValue() - 1) {
            redpeck = remain;
        } else {
            redpeck = remain.multiply(new BigDecimal(rand[i]))
                .divide(bigDecimal, 2, RoundingMode.FLOOR);
        }
        if (remain.compareTo(redpeck) > 0) {
            remain = remain.subtract(redpeck).setScale(2, BigDecimal.ROUND_HALF_UP);
        } else {
            remain = BigDecimal.ZERO;
        }
        sum1 = sum1.add(min.add(redpeck).setScale(2, BigDecimal.ROUND_HALF_UP));
        System.out.println("第" + (i + 1) + "個人搶到紅包金額為:" + min.add(redpeck));
    }

    System.out.println("紅包總額:" + sum1);
}
// 測試程式碼
public static void main(String[] args) {
    BigDecimal amount = new BigDecimal(100).setScale(2, BigDecimal.ROUND_HALF_UP);
    BigDecimal min = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
    BigDecimal num = new BigDecimal(10).setScale(2, BigDecimal.ROUND_HALF_UP);
    testPocket2(amount,min,num);
}
複製程式碼

為啥春節搶紅包總不是手氣最佳?看完微信搶紅包演算法你就明白了

他的隨機性也比較大,但是他最致命的是效能,因為他需要進行切割這個步驟。

演算法四:二倍均值法

演算法四就是微信紅包目前所採用的的演算法(大致思路,程式碼模擬),二倍均值計算公式:2 * 剩餘金額/剩餘紅包數。

  BigDecimal remain = amount.subtract(min.multiply(num));
    final Random random = new Random();
    final BigDecimal hundred = new BigDecimal("100");
    final BigDecimal two = new BigDecimal("2");
    BigDecimal sum = BigDecimal.ZERO;
    BigDecimal redpeck;
    for (int i = 0; i < num.intValue(); i++) {
        final int nextInt = random.nextInt(100);
        if(i == num.intValue() -1){
            redpeck = remain;
        }else{
            redpeck = new BigDecimal(nextInt).multiply(remain.multiply(two).divide(num.subtract(new BigDecimal(i)),2,RoundingMode.CEILING)).divide(hundred,2, RoundingMode.FLOOR);
        }
        if(remain.compareTo(redpeck) > 0){
            remain = remain.subtract(redpeck).setScale(2, BigDecimal.ROUND_HALF_UP);
        }else{
            remain = BigDecimal.ZERO;
        }
        sum = sum.add(min.add(redpeck)).setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println("第"+(i+1)+"個人搶到紅包金額為:"+min.add(redpeck));
    }
    System.out.println("紅包總額:" + sum);
}
複製程式碼

為啥春節搶紅包總不是手氣最佳?看完微信搶紅包演算法你就明白了

他還是比較好的保證了每個紅包金額大致相等,不會出現極端情況。

分類: 健康
時間: 2022-01-13

相關文章

阿司匹林腸溶片,長期吃有三大副作用!能不能停一段時間?

阿司匹林腸溶片,長期吃有三大副作用!能不能停一段時間?
"我因為有冠心痛.心絞痛的病症,所以一直有服用阿司匹林,但是最近感覺有點不對勁,胃老是反酸,都沒什麼食慾,還燒心,所以,想問問可以把阿司匹林停了嗎,或者更換成其它的藥物?" 心血管 ...

長期服用阿司匹林,怎樣才安全,醫生提醒:這4點要注意

長期服用阿司匹林,怎樣才安全,醫生提醒:這4點要注意
阿司匹林是一種經典的非甾體抗炎藥,含有水楊酸鹽,最早用於緩解疼痛.退燒和減輕炎症,應用已有100多年了. 後來科學研究發現,小劑量的阿司匹林具有抗血小板聚集的作用,減少血栓形成,近幾十年來廣泛用於腦梗 ...

長期服用阿司匹林和他汀,是在治療腦梗死嗎,真正目的是什麼?

長期服用阿司匹林和他汀,是在治療腦梗死嗎,真正目的是什麼?
阿司匹林和他汀是人們最常備用的藥,尤其是對老年人來說.阿司匹林可是緩解疼痛的神藥,而他汀是非常有效降血脂藥物,阿司匹林同樣也有擴張血管的作用,兩者對於緩解和治療老年人心腦血管疾病都能起到不小的作用. ...

長期服用阿司匹林和他汀,是在治療腦梗死嗎?它的真正目的是什麼

長期服用阿司匹林和他汀,是在治療腦梗死嗎?它的真正目的是什麼
一.頭暈,眼花不在意,最後竟直接送去醫院! 55歲的陳伯是地地道道的農村人,平常除了收拾家裡的田地,也經常去做村裡的泥水工賺點小錢.陳伯看起來精瘦有力,能幹能吃,也沒見他平常生過什麼大病.就是十年前診 ...

阿司匹林防血栓,70歲以上還能吃嗎?這部分朋友,不吃或有大風險

阿司匹林防血栓,70歲以上還能吃嗎?這部分朋友,不吃或有大風險
阿司匹林雖然是一個上市百年的老牌藥物,但由於其臨床應用範圍的不斷擴充套件,到現在為止,特別是在心血管疾病預防領域,阿司匹林仍然是一個重要的基礎藥物.對於抵抗血小板聚集,預防動脈粥樣硬化性心血管疾病風險 ...

腔隙性腦梗塞,需要長期用活血化瘀中藥嗎?醫生:你想得太簡單了

腔隙性腦梗塞,需要長期用活血化瘀中藥嗎?醫生:你想得太簡單了
劉先生今年43歲了,平常非常注重身體保養,也會定期和妻子去做身體體檢,可這次體檢卻發現檢測報告單上赫然寫著"多發腔隙性腦梗死".劉先生心裡一驚,感覺非常害怕,自己年紀也不大,怎麼會 ...

阿司匹林什麼時候吃最好?是飯前還是飯後?早上還是晚上?

阿司匹林什麼時候吃最好?是飯前還是飯後?早上還是晚上?
面對一種藥物,人們自然而然地會問,這個藥是飯前吃還是飯後吃?早上吃還是晚上吃?阿司匹林作為臨床上最常用的抗血小板藥物,當然也不例外.對於冠心病和腦梗死患者來說,阿司匹林幾乎是不可替代的.那麼,阿司匹林 ...

阿司匹林、硝酸甘油、速效救心丸,急救用哪種?牢記3句話

阿司匹林、硝酸甘油、速效救心丸,急救用哪種?牢記3句話
在心腦血管病的治療.預防和急救中,有三種藥,我們最為熟悉:硝酸甘油.速效救心丸和阿司匹林.它們中:有的能在心梗突發時用來急救:有的能很快緩解胸悶心悸等冠心病的突發症狀:有的能幫助高危人群預防心腦血管病 ...

阿司匹林和他汀要吃多久?什麼時候可以停?讓醫生來告訴你

阿司匹林和他汀要吃多久?什麼時候可以停?讓醫生來告訴你
57歲的李先生,患有高血壓已經七八年了.三年前出現心悸.胸悶發慌.胸口疼痛等症狀.剛開始李先生沒在意,有天晚上心絞痛的睡不著,李先生的妻子喊醒兒子,讓兒子起床開車帶父親去醫院檢查一下. 李先生的兒子帶 ...

長期不發燒的人,更容易得癌症,這是真的嗎?醫生告訴您真相

長期不發燒的人,更容易得癌症,這是真的嗎?醫生告訴您真相
"人體如果很少被病毒.細菌攻擊,免疫力就不會得到鍛鍊,那自然免疫力就不強,這樣的話就容易得癌症!" 張大爺是一個特別注意養生的人,他平時喜歡看一些健康相關的文章和影片.最近在瀏覽網 ...

吃阿司匹林和他汀,去醫院複查做哪些專案?哪些指標是重點?

吃阿司匹林和他汀,去醫院複查做哪些專案?哪些指標是重點?
導語:這個月有好幾位腦梗死患者去醫院做了詳細的複查,他們把檢查的結果都給我發過來,讓我幫忙給看一下.其實我不僅會幫助大家看這些抽血化驗的報告,而且還會感覺到特別的欣慰與開心. 因為看到這幾位腦梗死患者 ...

“神藥”阿司匹林真的可以放心吃?

“神藥”阿司匹林真的可以放心吃?
82歲的張嗲(化名),身體健朗,每天堅持在南郊公園晨練.近日,張嗲在晨練過程中突然暈倒在地,嘔吐,神志不清,在朋友的幫助下,立即送往湖南省腦科醫院(湖南省第二人民醫院)神經外科二病區進行救治,入院診斷 ...

人體最佳補鈣時間,是早上還是晚上?聽聽醫生怎麼

人體最佳補鈣時間,是早上還是晚上?聽聽醫生怎麼
鈣是一種礦物質,以其在骨骼健康中的關鍵作用而聞名.鈣也有助於保持心臟節律,肌肉的功能等.醫學研究所制定了膳食參考攝入量 (DRI) 和推薦的每日鈣攝入量 (RDA) 標準.從大家吃的食物中獲得這個量, ...

關注血脂,預防心腦血管疾病!哪些人需要化驗血脂?化驗哪幾項?

關注血脂,預防心腦血管疾病!哪些人需要化驗血脂?化驗哪幾項?
血脂是人體血液中脂類物質的的總稱,也是人體完成細胞代謝必不可少的物質,但是當人體內的血脂過高,就可能會在人體血管內皮沉積,逐漸形成動脈粥樣硬化斑塊.當斑塊逐漸增多.變大之後,血管腔就會慢慢變得狹窄,嚴 ...

兩個柑橘下去,老太太肝損了 服藥期間不僅不能飲酒飲茶,還要避開水果
專家名片 肖昌錢 副主任藥師,醫學碩士.浙江大學醫學院附屬浙江醫院藥劑科主任助理,臨床藥學組組長,長期從事老年心血管.心臟康復臨床藥學工作.兼任中國心臟聯盟心血管疾病預防與康復學會浙江聯盟第一屆委員. ...

突發心梗,急救藥選哪種?

突發心梗,急救藥選哪種?
當今社會的生活節奏不斷加快,加班到深夜已經成為不少人的常態,相對應的就是各種急慢性疾病的高發.對於一生操勞的中老年人,心肌梗死已經成為威脅生命健康的頭號隱患. 今年53歲的趙先生在一次應酬後突然感覺上 ...

頸動脈堆積“斑塊垃圾”,容易引發卒中、冠心病,專家喊你“打掃清理”

頸動脈堆積“斑塊垃圾”,容易引發卒中、冠心病,專家喊你“打掃清理”
作者:衣曉峰 隨著人們健康意識的逐步提高,越來越多的人會在體檢報告中發現自己得了"頸動脈粥樣硬化斑塊".因此許多人發問,什麼是頸動脈粥樣硬化斑塊?這種斑塊是怎麼來的?哪個年齡段的人 ...

冠心病患者不能忽視的5個細節

冠心病患者不能忽視的5個細節
冠心病 很多患者來看心血管門診,有的人因為晨練後出現心慌.胸悶甚至胸痛來就診:有的人為了"疏通血管",要求醫生開靜脈輸液:還有一些是進行常規復查的心臟病患者.對冠心病患者來講,以下 ...

有種血管病像痴呆!神經內科專家:出現這些非典型症狀要警惕

有種血管病像痴呆!神經內科專家:出現這些非典型症狀要警惕
來源:生命時報 復旦大學附屬華山醫院神經內科副主任醫師 程 忻 陳先生今年86歲,最近總頭疼,以為是感冒了並沒在意,但之後幾天,他的反應越來越慢,偶爾還會胡言亂語,家人急忙將其送往醫院.經檢查發現老人 ...

胃不舒服、反酸、燒心…試試這個新妙招,有用

胃不舒服、反酸、燒心…試試這個新妙招,有用
你有沒有體驗過這些感覺? 反酸.燒心.打嗝.噁心. 嘔吐.胃脹.胃痛-- 六十多歲的王先生(化名)長期受此困擾. "我每天都必須吃胃藥來控制症狀,一停藥就復發,嚴重影響生活啊!" ...