search

Home  >  Q&A  >  body text

php - 面试问题:发一个随机红包,100块钱给10个人。每个人最多12块钱,最少6块钱。怎么分?

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

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

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

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

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

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

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

高洛峰高洛峰2788 days ago6308

reply all(41)I'll reply

  • PHP中文网

    PHP中文网2017-04-11 09:56:50

    一个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);
    
    ?>

    reply
    0
  • 高洛峰

    高洛峰2017-04-11 09:56:50

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

    reply
    0
  • 高洛峰

    高洛峰2017-04-11 09:56:50

    $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));

    reply
    0
  • ringa_lee

    ringa_lee2017-04-11 09:56:50

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

    reply
    0
  • PHP中文网

    PHP中文网2017-04-11 09:56:50

     <?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));
        // 感觉还有可以完善的地方,先这样吧
    

    reply
    0
  • 阿神

    阿神2017-04-11 09:56:50

    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);
    

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

    reply
    0
  • PHP中文网

    PHP中文网2017-04-11 09:56:50

    半夜看到这个问题,忽然想到二分法那种模式,于是搞了一个解决方案,先讲思路。
    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

    reply
    0
  • 阿神

    阿神2017-04-11 09:56:50

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

    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;
    }

    reply
    0
  • 怪我咯

    怪我咯2017-04-11 09:56:50

    
    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();
    
            }
    

    reply
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-11 09:56:50

    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 就停止

    reply
    0
  • Cancelreply