不同中獎概率的多獎包抽獎幾種演算法
阿新 • • 發佈:2019-02-02
需求描述:總共有很多個獎包,每個獎包的中獎概率是人為自由設定的,規定每次抽獎必須抽中。
演算法分類:
一、最初自行編寫的演算法:
<?php
//目標id:隨機抽中的獎包id
$pid = 0;
//$pList為獎包資訊存放陣列,是從資料庫中提取出來的
//為方便研究,這裡直接給$pList賦值
$pList = array
(
[0] => array
(
['id'] => 65,
['percent'] => 10
),
[1] => array
(
['id' ] => 64,
['percent'] => 50
),
[2] => array
(
['id'] => 63,
['percent'] => 20
),
[3] => array
(
['id'] => 62,
['percent'] => 80
),
[4] => array
(
['id' ] => 61,
['percent'] => 30
)
);
//中獎概率之總和
$sum = 0;
//以中獎概率總和為上限,以1為起始鍵名(1為自增值),以表的id為鍵值的陣列
//ps:本想直接給$randomArr賦值,上面的程式碼也省略,但這樣不利於理解和對比
$randomArr = array();
if(!empty($pList)){
foreach($pList as $key=>$value){
$newSum = $sum + $value['percent'];
for($i=$sum +1;$i<=$newSum;$i++){
//給$randomArr賦值,中獎概率為鍵名,id為鍵值
$randomArr[$i] = $value['id'];
}
$sum = $newSum;
}
}
//隨機出的數,作為抽中的$randomArr陣列的鍵名
$random = 0;
if($sum > 0){
$random = mt_rand(1,$sum);
}
//確定隨機抽中的獎包id
if($random > 0){
$pid = $randomArr[$random];
}
思路:用中獎概率為鍵名,獎包id為鍵值組建陣列 => 隨機鍵名(中獎概率) => 根據鍵名確定鍵值(獎包id)
總結:優點是利於理解,缺點是效率不高
二、經領導指點改進後的演算法:
<?php
//目標id:隨機抽中的獎包id
$pid = 0;
//$pList為獎包資訊存放陣列,是從資料庫中提取出來的
//為方便研究,這裡直接給$pList賦值
$pList = array
(
[0] => array
(
['id'] => 65,
['percent'] => 10
),
[1] => array
(
['id'] => 64,
['percent'] => 50
),
[2] => array
(
['id'] => 63,
['percent'] => 20
),
[3] => array
(
['id'] => 62,
['percent'] => 80
),
[4] => array
(
['id'] => 61,
['percent'] => 30
)
);
//中獎概率之總和
$sum = 0;
//中獎概率存放陣列,以id為鍵名,以中獎概率的累加和為鍵值
//賦值後的$randomArr,形如$randomArr = array(0=>0,65=>10,64=>50,...,61=>30);
$randomArr = array();
//為了方便下面隨機數範圍的比較而設定
$randomArr[0] = 0;
if(!empty($pList)){
foreach($pList as $key=>$value){
$sum = $sum + $value['percent'];
$randomArr[$value['id']] = $sum;
}
}
//隨機出的概率數
$random = 0;
if($sum > 0){
$random = mt_rand(1,$sum);
}
//每次迴圈參加比較的上一個key的值
$oldKey = 0;
foreach($randomArr as $key=>$value){
if($key > 0){
//根據隨機數大小範圍比較,確定隨機出的獎包id
if($random>$randomArr[$oldKey] && $random<=$randomArr[$key]){
$pid = $key;
}
}
$oldKey = $key;
}
思路:用獎包id為鍵名,中獎概率累加和為鍵值組建陣列 => 隨機鍵值(中獎概率) => 判斷中獎概率的範圍 => 根據範圍確定鍵名(獎包id)
總結:優點是易於理解,且執行效率高,只是前期演算法設計時需多動腦筋
三、網路搜來的經典演算法:
<?php
//目標id:隨機抽中的獎包id
$pid = 0;
//$pList為獎包資訊存放陣列,是從資料庫中提取出來的
//為方便研究,這裡直接給$pList賦值
$pList = array
(
[0] => array
(
['id'] => 65,
['percent'] => 10
),
[1] => array
(
['id'] => 64,
['percent'] => 50
),
[2] => array
(
['id'] => 63,
['percent'] => 20
),
[3] => array
(
['id'] => 62,
['percent'] => 80
),
[4] => array
(
['id'] => 61,
['percent'] => 30
)
);
//中獎概率之總和
$sum = 0;
if(!empty($pList)){
//求$sum的值
foreach($pList as $key=>$value){
$sum = $sum + $value['percent'];
}
//根據數學概率論的“黑箱摸球”原理設計、取得抽中的獎包id
if($sum > 0){
foreach($pList as $key=>$value){
//以剩餘迴圈概率和為基數,生成隨機數
$random = mt_rand(1,$sum);
//若生成的隨機數在本次迴圈的中獎概率範圍內,則抽中本獎包,迴圈終止
if($random <= $value['percent']){
$pid = $value['id'];
break;
}else{
//若迴圈未終止,則每迴圈一次,$sum需要減去本次迴圈的中獎概率
$sum -= $value['percent'];
}
}
}
}
思路:參考數學概率論的“黑箱摸球”
總結: 前人實踐證實可用且執行效率高,只是概率論學得不好的童鞋理解起來較困難
領悟:好的演算法不止要易於理解,還要兼顧執行效率、系統安全和穩健等因素,所以程式設計之前要開動腦筋、利用手頭資源多準備幾種演算法,綜合考慮比較後再做決定