/**
* 二倍均值法随机红包算法
* @param $totalAmount 总金额 单位为分
* @param $minAmount 最少金额 单位为分
* @param $totalNum 人数
* @return array
*/
function redPacket($totalAmount, $totalNum, $minAmount = 1)
{
// 每人至少{$minAmount}分
if ($minAmount * $totalNum > $totalAmount) return [];
$result = [];
$restAmount = $totalAmount;
$restNum = $totalNum;
for ($i = 0; $i < $totalNum - 1; $i++) {
// 随机范围[1,剩余人均金额的两倍),左闭右开
$amount = mt_rand($minAmount, floor($restAmount / $restNum) * 2 - $minAmount);
$restAmount -= $amount;
$restNum--;
array_push($result, $amount / 100);
}
array_push($result, $restAmount / 100);
return $result;
}
$money = 0.5 * 100;
$num = 50;
$result = redPacket($money, $num);
if (empty($result)) die('红包金额有误') . "\n";
print_r($result);
echo "\n总计:" . array_sum($result) . "\n";
echo "\n手气最佳为:" . max($result) . "\n";
echo "\n手气最差为:" . min($result) . "\n";
说明:
公式:(0, M/N * 2),M为剩余红包金额,N为剩余人数,这个公式,保证了每次随机金额的平均值是相等的,不会因为抢红包的先后顺序而造成不公平。
举例说明:
假设有10个人,红包总额100元。
100/10X2 = 20, 所以第一个人的随机范围是(0,20 ),平均可以抢到10元。
假设第一个人随机到10元,那么剩余金额是100-10 = 90 元。
90/9X2 = 20, 所以第二个人的随机范围同样是(0,20 ),平均可以抢到10元。
假设第二个人随机到10元,那么剩余金额是90-10 = 80 元。
80/8X2 = 20, 所以第三个人的随机范围同样是(0,20 ),平均可以抢到10元。
以此类推,每一次随机范围的均值是相等的。
- 缺点:除了最后一次,任何一次抢到的金额都要小于人均金额的两倍,并不是任意的随机。