题目:有金额M元,给N个人发红包,最低0.01元,完全随机,不设上限,全部金额都需发放出去。

思路:可以借鉴发牌的算法,将金额以最小发放单位0.01元换算,等价于M*100张牌。那么我们要做的是,从M*100张牌里边随机抽出N-1张牌,计算这N-1张牌中间隔出来的N个区间的差值即可。

 

复制代码
<?php
$total = 100;
$num = 10;

$ret = assignMoney($total, $num);
echo implode(',', $ret) . PHP_EOL;
assert(array_sum($ret) == $total);
 
/**
 * 发放红包
 */
function assignMoney($total, $num)
{
    // 只有1个人分时,总是全部给他就行
    if ($num == 1) {
        return [$total];
    }
    // 如果总数和人数一样,则每人都得1分钱
    if ($total == $num) {
        return array_fill(0, $num, 1);
    }
    // 将每一分钱排成1个数组
    $moneys = [];
    for ($i = 0; $i < $total; $i++) {
        $moneys[] = $i + 1;
    }
    // 从中随机选出[总数-1]个元素
    $indexs = [];
    $realNum = min($total, $num);
    $max = count($moneys) - 2;
    for ($i = 0; $i < $realNum - 1; $i++) {
        $index = random_int(0, $max);
        $indexs[] = $moneys[$index];
 
        // 已选中的元素排除出去
        $moneys[$index] = $moneys[$max];
        $max--;
    }
    // 将选出的数组排好序
    sort($indexs, SORT_NUMERIC);
    // 计算出每个元素间隔的元素个数,也就是需要发红包的数量
    $ret = [$indexs[0]];
    for ($i = 0; $i < $realNum - 2; $i++) {
        $ret[] = ($indexs[$i + 1] - $indexs[$i]);
    }
    $ret[] = $total - $indexs[$realNum - 2];
    return $ret;
}
?>
posted on 2020-08-24 10:40  李留广  阅读(218)  评论(0编辑  收藏  举报