php - 面试问题:发一个随机红包,100块钱给10个人。每个人最多12块钱,最少6块钱。怎么分?
高洛峰
高洛峰 2017-04-11 09:54:50
0
41
6258

以前想过一个类似问题,就是没有每个人最大、最小的得钱数的限制,以前的问题可以很好用随机数解决。

于是这个问题也被以前的思想带坑里了,把突破口完全放在了如何处理每个人的随机数上。

于是在面试时间就没有解决这个问题,直到面试结束自己安静下来,仔细想想,发现思路错了。

我认为正确的思路是:每个人先得6块钱,这样剩下40块钱,之后每次拿出一块钱,随机分配给一个人,如果某个人的钱数达到了上限,那么这个人下次就没有了再得到钱的资格了。这样直到剩下钱都分配完。

当然在接口的实际处理上可以做些优化,例如剩下的钱每次随机分配的钱可以是随机的(当然这个随机要做一些限制,以免一下就分配超额了),然后如果某个人钱+这次随机分配的钱>每个人的上限,那么他就没有资格得到这个钱了。

随机分配也好实现,先算有几个人有资格得到这笔钱,随即一个数,决定给第几个符合资格的人。

我的思路就是这样,大家如果有更好的思路,请告知。谢谢。

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

全部回复(38)
Ty80

一个do while循环就能解决的问题,搞那么复杂。

<?php

$money  = 40;
$people = array_fill(0, 10, 6);

do {

    $lucky_index = mt_rand(0, 9);
    $lucky_money = floatval(substr(mt_rand() / mt_getrandmax(), 0, 4));

    if($people[$lucky_index]+$lucky_money >= 12)
        continue;

    if($money < 1) {
        $m = $money;
    } else {
        $m = $lucky_money;
    }

    $people[$lucky_index] += $m;
    $money -= $m;

} while($money > 0);

print_r($people);

?>
小葫芦

你的想法基本靠谱,我认为可以这样分:
1.先每人分6元,还剩下40元。
2.起一个循环,每人分0-(12-他已有的钱)元随机,直到钱分完为止。
没有题主讲的这么麻烦的。

小葫芦
$arr = [];
for ($i=0; $i < 9; $i++) { 
    $arr[] = mt_rand(6,12);
}
array_push($arr, 100 - array_sum($arr));
var_dump($arr);
var_dump(array_sum($arr));
左手右手慢动作

先每个人分6分,然后把剩下的钱再分
这个时候取10个随机值(0-9)随意,然后取各个值在随机值总和的百分比,分别乘以剩下的10000-60;Math.ceil或者Math.floor都可以
最后一个值防止取ceil时溢出,直接用10000-60-前面九个数的和即可
然后分别加上6,换算即可

洪涛
 <?php
    // 1.初始化,平均分配每人$initAvgMoney(根据限制条件随机产生)
    // 2.每人随机拿出一定金额到共享资金池中,进行重新分配
    // 限制条件:$initAvgMoney应满足条件:"小宝"一分钱也不放入共享资金池("特自私"),其余九人拿出尽可能多的钱到共享资金池(每人只留6元)的情况下,共享资金池平均分配后小宝的钱也不超过12块

    header("Content-type:text/html;charset=utf-8");
    $minInitAvgMoney = 600;
    // ($maxInitAvgMoney - 600) * 9 / 10 + $maxInitAvgMoney <= 1200;
    $maxInitAvgMoney = floor(1740 / 1.9);
    echo("maxInitAvgMoney:");var_dump($maxInitAvgMoney);
    
    $initAvgMoney = mt_rand($minInitAvgMoney, $maxInitAvgMoney) ;
    echo("initAvgMoney:");var_dump($initAvgMoney);
    
    $maxMinus = $initAvgMoney - 600;
    echo("maxMinus:");var_dump($maxMinus);
    
    
    $moneyArr = array();
    for($i = 0; $i < 10; $i ++){
        $randMinusArr[$i] = mt_rand(0, $maxMinus / 10) * 10;
        // echo("randMinusArr-{$i}");var_dump($randMinusArr[$i]);
        $moneyArr[$i] = $initAvgMoney - $randMinusArr[$i];
    }
    
    
    $randMinusSum = 10000 - $initAvgMoney * 10 + array_sum($randMinusArr);
    
    $avgAddMoney = $randMinusSum / 10;
    
    for($i = 0; $i < 10; $i ++){
        $moneyArr[$i] = ($moneyArr[$i] + $avgAddMoney) / 100;
    }
    
    echo "最终结果:";var_dump($moneyArr);
    echo "结果验证:";var_dump(array_sum($moneyArr));
    // 感觉还有可以完善的地方,先这样吧
阿神
min = 6;
max = 12;
total = 100;
pe = 10;
maxTotal = max*pe - total;

list = array();
for (0<pe)
    if(maxTotal>0)
        temp = random(0,maxTotal>=6?6:maxTotal);
        maxTotal-=temp;
        list.push(12-temp);
        
if(maxTotal>0)
    pre = maxTotal/pe;
    for (0<pe)list[temp2]+=pre;
 
shuffle(list);

此方法是错误的,没有强迫症,不修改了

洪涛

半夜看到这个问题,忽然想到二分法那种模式,于是搞了一个解决方案,先讲思路。
1.先将人分为两半,左半人分的总金额最少是左半人数x最少金额总金额-右半人数x最多金额两个数字中较大的;
2.左半人分的总金额最多是左半人数x最多金额总金额-右半人数x最少金额两个数字中较小的;
3.在这个范围内取随机数作为分给左半人的金额,然后将问题递归为左半人分钱和右半人分钱。
py代码(直接以分为单位,数字都是整数):

import random

def deliver(sum_of_money,num_of_people,min_of_money,max_of_money):
    if num_of_people==1:
        arr = [sum_of_money]
        return arr
    else:
        half = num_of_people>>1
        border_left = max(min_of_money*half,(sum_of_money-(num_of_people-half)*max_of_money))
        border_right = min(max_of_money*half,(sum_of_money-(num_of_people-half)*min_of_money))
        sum_of_left = random.randint(border_left,border_right)
        arr_left = deliver(sum_of_left,half,min_of_money,max_of_money)
        arr_right = deliver(sum_of_money-sum_of_left,num_of_people-half,min_of_money,max_of_money)
        return arr_left+arr_right
        
list = deliver(10000,10,600,1200)
print list
阿神

根据题主的思路写了这样的一个答案

function faHongBao(money, pe, min, max) {
    var sum = money,
        result = [];

    for(var i=0; i<pe; i++) {
        result.push(min);
        sum -= min;
    }

    while(sum > 0) {
        var ran = Math.floor( Math.random() * (pe - 1) );
        if(result[ran] < max) {
            result[ran]++;
            sum--;
        }
    }

    return result;
}

刘奇

static void Main(string[] args)
        {
            int all = 100;//总金额
            int person = 10;//人数
            double min = 8;//最小金额
            double max = 12;//最大金额

            double[] array = new double[person];//分配结果集
            int i = 0;//第几人
            Random ran = new Random();

            //默认分配最小值
            for (i = 0; i < person; i++)
            {
                array[i] = min;
            }

            double yet = min * person;//已分配金额

            int whileTimes = 0;//记录循环次数
            while (yet < all)
            {
                double thisM = Math.Round((ran.NextDouble() * (max - min - 1)), 2);
                i = ran.Next(0, person);
                if (yet + thisM > all)
                {
                    thisM = all - yet;
                }

                if (array[i] + thisM < max)//判断是否超出最大金额
                {
                    array[i] += thisM;
                    yet += thisM;
                }
                whileTimes++;
            }


            Console.Write("共循环{0}次\r\n", person + whileTimes);
            yet = 0;
            for (i = 0; i < person; i++)
            {
                yet += array[i];
                Console.Write("第{0}人=>分配{1}元,合计分配{2}元\r\n", i + 1, array[i], yet);
            }
            Console.Read();

        }
伊谢尔伦
function roundmoney()
    {
        $cash=100;
    
        for ($i = 0; $i < 10; $i++) {
            $people[$i]=rand(6,12);
            $cash=$cash-$people[$i];
            if($cash==0&&$i==9)
            {
                return $people;
            }
        }
        return false;
    
    }
    while(true)
    {
        if(($res=roundmoney())!=false)
        {
            var_dump($res);
            break;
        }
    
    }

感觉有点粗暴,就是完全让计算机随机分,什么时候刚好分够10个人并且每个人不少于6不大于10 就停止

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板