1. 程式人生 > >抽獎概率-三種演算法

抽獎概率-三種演算法

一、逢“幾”中獎

逢“幾”中獎,即通過預估抽獎人數和獎品數來判斷,“幾”=(抽獎人數/獎品數)*N。這是一種最簡單抽獎演算法,適合抽獎人數眾多,而且互相無聯絡的情況。如今大為流行的微博轉發得獎就常常使用這種演算法,即根據轉發次數來決定獎品歸屬,透明而且具有激勵性。

當然這個“幾”也不單隻次數,還可能是時間,逢某個時間點就可以抽中,不過這種方案可能產生無人中獎和很多人中獎的情況,時間點的安排很關鍵!這個時間點一旦公佈出去,那就是秒殺,霍霍。。

逢“幾”中獎有很多弊端,但是非常簡單,很容易實現,被很多抽獎活動所採用,有些會公佈抽獎規則,激勵抽獎,有些則不會公佈,其實後臺執行的可能也是這個演算法,簡單高效又不失公平。在資訊不透明的情況下,鬼知道你是第幾個抽獎的,哈哈。。

二、概率抽獎

所謂概率抽獎是最容易想到的抽獎演算法了,這個概率可以是一成不變的,也可以是一直在變化調整的,最難的是採用多大的概率,何種情況下采用何種概率。這個也沒有什麼通用的方案,不同的應用場景,所用的概率演算法不同。下面介紹一種演算法,根據獎品的過期日期來計算它當前時間的中獎率,當時間逐漸接近獎品過期時間時,中獎概率會逐漸發生變化,如果設為1表示線性衰減,2為平方衰減,以此類推。

複製程式碼
importjava.util.Date;

importjava.util.Random;

 

publicclass LotteryTool {

 

private double factor;

private double probability; private Random rand; private LotteryTool(double probability, long expireTime, int reduce){ this.factor = (double) System.currentTimeMillis() / expireTime; this.probability = probability * Math.pow(factor, reduce); this.rand = new Random(System.currentTimeMillis()); }
public static LotteryTool getInstance(double probability, longexpireTime, int reduce) { return new LotteryTool(probability, expireTime, reduce); } public boolean isLucky(long expected) { long token = generateLong(); expected = expected % (int) (1 / probability); if (expected == token) { return true; } return false; }
複製程式碼

三、依賴不可控的物理隨機數 

什麼意思呢,先看個圖,看完你就知道了

 看完你就知道了

明白了吧,呵呵,這就是現如今灰常流行的一種抽獎演算法,絕對公平、絕對透明、絕對木有暗箱(除非偷偷給你換了抽獎號碼)!但是這種方法唯一的缺點是無法實時抽獎,只能事後抽獎。也就是隻能拿個抽獎號等著上帝的眷顧,阿門。。。

例如遊戲中打敗一個boss,會掉落下面其中一個物品,而每個物品都有一定概率: 1. 靴子 20% 2. 披風 25% 3. 飾品 10% 4. 雙手劍 5% 5. 金幣袋 40% 現在的問題就是如何根據概率掉落一個物品給玩家。

一. 一般演算法:生成一個列表,分成幾個區間,例如列表長度100,1-20是靴子的區間,21-45是披風的區間等,然後隨機從100取出一個數,看落在哪個區間。演算法時間複雜度:預處理O(MN),隨機數生成O(1),空間複雜度O(MN),其中N代表物品種類,M則由最低概率決定。

二、離散演算法:也就是上面的改進,竟然1-20都是靴子,21-45都是披風,那抽象成小於等於20的是靴子,大於20且小於等於45是披風,就變成幾個點[20,45,55,60,100],然後也是從1到99隨機取一個數R,按順序在這些點進行比較,知道找到第一個比R大的數的下標,比一般演算法減少佔用空間,還可以採用二分法找出R,這樣,預處理O(N),隨機數生成O(logN),空間複雜度O(N)。 請點選檢視詳細:http://www.cnblogs.com/miloyip/archive/2010/04/21/1717109.html

三、Alias Method Alias Method就不太好理解,實現很巧妙,推薦先看看這篇文章:http://www.keithschwarz.com/darts-dice-coins/ 大致意思:把N種可能性拼裝成一個方形(整體),分成N列,每列高度為1且最多兩種可能性,可能性抽象為某種顏色,即每列最多有兩種顏色,且第n列中必有第n種可能性,這裡將第n種可能性稱為原色。 想象丟擲一個硬幣,會落在其中一列,並且是落在列上的一種顏色。這樣就得到兩個陣列:一個記錄落在原色的概率是多少,記為Prob陣列,另一個記錄列上非原色的顏色名稱,記為Alias陣列,若該列只有原色則記為null。

之前的例子,為了便於演示換成分數 1. 靴子 20% -> 1/4 2. 披風 25% -> 1/5 3. 飾品 10% -> 1/10 4. 雙手劍 5% -> 1/20 5. 金幣袋 40% -> 2/5 然後每個都乘以5(使每列高度為1),再拼湊成方形 拼湊原則:每次都從大於等於1的方塊分出一小塊,與小於1的方塊合成高度為1

由上圖方形可得到兩個陣列: Prob: [3/4, 1/4, 1/2, 1/4, 1] Alias: [4, 4, 0, 1, null] (記錄非原色的下標)

之後就根據Prob和Alias獲取其中一個物品 隨機產生一列C,再隨機產生一個數R,通過與Prob[C]比較,R較大則返回C,反之返回Alias[C]。

Alias Method 複雜度:預處理O(NlogN),隨機數生成O(1),空間複雜度O(2N)

相關推薦

抽獎概率-演算法

一、逢“幾”中獎 逢“幾”中獎,即通過預估抽獎人數和獎品數來判斷,“幾”=(抽獎人數/獎品數)*N。這是一種最簡單抽獎演算法,適合抽獎人數眾多,而且互相無聯絡的情況。如今大為流行的微博轉發得獎就常常使用這種演算法,即根據轉發次數來決定獎品歸屬,透明而且具有激勵性。 當然這個

OpenCV邊緣檢測演算法(canny、sobel、laplacian)

Canny演算法 #include<opencv2\opencv.hpp> #include<opencv2\highgui\highgui.hpp> using namespace std; using namespace cv; //邊緣檢測 int mai

最短路和差分約束(演算法實現)( Til the Cows Come Home )

題目訓練連結(密碼hpuacm): https://vjudge.net/contest/246705 我會分別用 迪傑斯特拉  優先佇列和鏈式前向星優化過的迪傑斯特拉  SPFA演算法 三種方法講一下例題。 此外上述三種演算法是求單源最短路問題, 這裡還會

如何做好文字關鍵詞提取?從演算法說起

在自然語言處理領域,處理海量的文字檔案最關鍵的是要把使用者最關心的問題提取出來。而無論是對於長文字還是短文字,往往可以通過幾個關鍵詞窺探整個文字的主題思想。與此同時,不管是基於文字的推薦還是基於文字的搜尋,對於文字關鍵詞的依賴也很大,關鍵詞提取的準確程度直接關係到推薦系統或者搜尋系統的最終

最大流EK、Dinic、SAP演算法模板

EK   //Max_flow //@2018/05/02 Wednesday //EK algorithm [Edmonds Karp] O(V*E^2) O(v^2) //by Tawn #include <bits/stdc++.h> using nam

最短路問題(演算法與路徑還原演算法

1、Bellman-Ford演算法: 用Bellman-Ford演算法求解單源最短路徑問題,單源最短路徑是指固定一個起點,求它到其他所有點的最短路問題。 struct edge { int from, to, cost; //從頂點from指向頂點to的權值為c

C語言求最小公倍數和最大公約數演算法(經典)

求最小公倍數演算法: 最小公倍數=兩整數的乘積÷最大公約數 求最大公約數演算法: (1)輾轉相除法 有兩整數a和b: ① a%b得餘數c ② 若c=0,則b即為兩數的最大公約數 ③ 若c≠0,則a=b,b=c,再回去執行① 例如求27和15的最大公約數過程為:

【轉載】快速排序(演算法實現和非遞迴實現)

原文地址 python實現: import random a = [4,1,7,6,9,2,2,3,5,7,8,9,3,1,2,3,4,5,8,0,3,5] b = [4,1,7,6,9,2,8,0,3,5] def twoPointerSort(nums,le

C語言求最小公倍數和最大公約數演算法(經典)----ACM

最小公倍數:數論中的一種概念,兩個整數公有的倍數成為他們的公倍數,其中一個最小的公倍數是他們的最小公倍數,同樣地,若干個整數公有的倍數中最小的正整數稱為它們的最小公倍數,維基百科:定義點選開啟連結 求最小公倍數演算法: 最小公倍數=兩整數的乘積÷最大公約數 求最大公

最長遞增子序列的演算法

問題 給定一個長度為N的陣列,找出一個最長的單調自增子序列(不一定連續,但是順序不能亂)。例如:給定一個長度為6的陣列A{5, 6, 7, 1, 2, 8},則其最長的單調遞增子序列為{5,6,7,8},長度為4. 解法1:最長公共子序列法 這個問題可以轉換為最長公共子序列問題。如例子中的陣列A{5,

技術乾貨 | 如何做好文字關鍵詞提取?從演算法說起

【資料猿導讀】 不管是基於文字的推薦還是基於文字的搜尋,對於文字關鍵詞的依賴也很大,關鍵詞提取的

快速排序(演算法實現和非遞迴實現)

快速排序(Quick Sort)是對氣泡排序的一種改進,基本思想是選取一個記錄作為樞軸,經過一趟排序,將整段序列分為兩個部分,其中一部分的值都小於樞軸,另一部分都大於樞軸。然後繼續對這兩部分繼續進行排序,從而使整個序列達到有序。 遞迴實現: void Q

細談遞迴,備忘錄遞迴,動態規劃,演算法思想和執行原理

大家都知道,數值稍大的遞迴執行時間對於開發者來說就是場災難,我們總是想方設法在優化遞迴,或者說不用遞迴,此文中從空間時間角度詳細剖析以上三種演算法的區別,以及執行原理,以斐波那契數為例, 程式語言java 此處為程式碼 package test

openCV人臉識別演算法實現(官網翻譯)

 怎樣使用OpenCV進行人臉識別 友情提示,要看懂程式碼前,你得先知道OpenCV的安裝和配置,會用C++,用過一些OpenCV函式。基本的影象處理和矩陣知識也是需要的。[gm:我是簫鳴的註釋]由於我僅僅是翻譯,對於六級才過的我,肯定有一些翻譯錯的或

三元組順序表-轉置運算-演算法

#include <stdio.h>  #include <stdlib.h>  #define MAXSIZE 1000 typedef int ElementType; typedef struct {int row;int col;Elemen

先來先服務,短作業優先,最高響應比演算法下求平均週轉和帶權週轉時間的實現

codear發表於 2006年04月11日 21:20:00 (http://blog.csdn.net/coDear) #include<iostream.h>#define N 6struct time{    float arriveTime;    fl

演算法求兩個正整數的最大公約數和最小公倍數;求個數的最大公約數和最小公倍數

第二次作業 題目:求兩個正整數的最大公約數和最小公倍數。 基本要求:1.程式風格良好(使用自定義註釋模板),兩種以上演算法解決最大公約數問題,提供友好的輸入輸出。 提高要求:1.三種以上演算法解決兩個正整數最大公約數問題。                    2.求

HDU 3549 Flow Problem 網路最大流問題 EK、Dinic、ISAP演算法

Flow Problem Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 8218    Accepted

不借助其它變數交換兩變數值的演算法

在學習程式語言和進行程式設計的時候,交換兩個變數的值是經常要使用的。通常我們的做法是(尤其是在學習階段):定義一個新的變數,藉助它完成交換。程式碼如下:int a,b;a=10; b=15;int t;t=a; a=b; b=t;這種演算法易於理解,特別適合幫助初學者瞭解計算機程式的特點,是賦值語句的經典應用

最短路小結(演算法+各種常見變種)

額,博主只是做了幾(約數)道題而已,寫這篇小結純粹想留作紀念(勿噴,但是可以交流)(那啥,轉載的話註明一下來源。。打字不容易。。) 最短路呢,包括三種演算法,但是各有各的變種,其中變化有很多。 簡單記錄一下。 首先是三種演算法: 1、Dijkstra演算