红包酬谢一个算法求帮助 概率算法

$arr = array(   
    array('id'=>1,'name'=>'特等奖','v'=>50),
    array('id'=>2,'name'=>'一等奖','v'=>20),
    array('id'=>3,'name'=>'二等奖','v'=>20),
    array('id'=>6,'name'=>'没中奖','v'=>10)
);

这有一个预设的奖品 但是现在的需求是 v越大中奖的概率越低 越小的中奖概率越大 更网上很多代码都不符合 求大神帮忙下 有红包酬谢

目前的算法为 v越大中奖概率越大 求大神帮忙:

  private function getRand($proArr)
    {
        $result = array();
        $arr = [];
        foreach ($proArr as $key => $val) {
            $arr[$key] = $val['v'];
        }
        // 概率数组的总概率
        $proSum = array_sum($arr);
        asort($arr);
        // 概率数组循环
        foreach ($arr as $k => $v) {
            $randNum = mt_rand(1, $proSum);
            if ($randNum <= $v) {
                $result = $proArr[$k];
                break;
            } else {
                $proSum -= $v;
            }
        }
        return $result;
    }
阅读 3.1k
3 个回答

先把所有v的倒数求和 s=∑(1/v)
然后每个中奖的概率按1/(v*s)算就好了

我一般的骚操作是 mt_rand(1, 100); 然后看结果落在哪个区间,如你的需求是 v越大中奖概率越低,反转意味着 结果值在 1-50区间的时候,为没中奖,而在90-100区间的时候为特等奖,甚至不需要什么算法了。

不知道这样能不能解决你的需求,为了灵活点,可以使用 range() 函数根据 v 值来生成数组也行,这样 in_array 判断一下,到时候调整概率就好调整了

<?php

$proArr = array(
    array('id'=>1,'name'=>'特等奖','v'=>50),
    array('id'=>2,'name'=>'一等奖','v'=>20),
    array('id'=>3,'name'=>'二等奖','v'=>20),
    array('id'=>6,'name'=>'没中奖','v'=>10)
);

/**
 * 取最大数做基数
 */
$base = max(array_column($proArr, "v"));
$min = 0;
foreach ($proArr as $key=>$pArr){
    $max = $min + round($base/$pArr['v']*100);
    $proArr[$key]['range'] = [
        "min" => $min,
        "max" => $max,
    ];
    $min = $max;
}

$result = [];
$r = mt_rand(0, $max-1);
foreach ($proArr as $key=>$pArr){
    if($r >= $pArr["range"]["min"] AND $r< $pArr["range"]["max"]){
        $result = $pArr;
        break;
    } else {}
}

var_dump($result);
推荐问题