検索

ホームページ  >  に質問  >  本文

php - 用程序生成n个随机数,要求n个数的和等于100

想破了头,也没想出来怎么算!!!

迷茫迷茫2795日前1835

全員に返信(25)返信します

  • 伊谢尔伦

    伊谢尔伦2017-04-10 16:36:47

    1, 先生成n个随机数
    2, 对这n个数的和m
    3, 用100除以m, 求出放大系数k
    4, n个随机数分别乘以k

    这个方法是有精度损失的, 我测试一般在99.9 - 100.1之间
    放个python3的代码

    import random
    
    def foo(n, m):
        numbers = [random.random() for _ in range(n)]
        summation = sum(numbers)
        k = m / summation
        return [i * k for i in numbers]
    
    if __name__ == '__main__':
        res = foo(10,100)
        print('10个数为:', res)
        print('它们的和为:', sum(res))
    

    输出:

    10个数为: [11.656631528447768, 16.926541353866945, 11.491003842424307, 15.187012385101323, 1.4760319842835616, 8.838953893828934, 14.315979522491865, 3.882534453021053, >8.290003662873072, 7.935307373661164]
    它们的和为: 99.99999999999999

    返事
    0
  • 迷茫

    迷茫2017-04-10 16:36:47

    不妨换个角度看这个问题,会简单很多:把100个1随机分配给N个数。所以循环100次,每次随机选中第1到N间的某个数,给它加1。
    如果要求不能有数为0,则一开始每个数初始化为1,然后只循环90次即可。

    返事
    0
  • PHP中文网

    PHP中文网2017-04-10 16:36:47

    (1,100)生成第一个数n1
    (1,100-n1)生成第二个n2
    ...
    最后一个是100-(n1+n2...)

    返事
    0
  • 大家讲道理

    大家讲道理2017-04-10 16:36:47

    假设是n个数。
    给你另一种思路,先有100这个数据池子,从里面每次随机取出一个数字,池子减少相应的数字,递归这个过程。
    当需要跳出递归,最后一次的数据取出全部。
    整个过程类似微信红包。唯一注意的时候,需要判断剩余的池子里能不能最少满足你的n。

    返事
    0
  • 巴扎黑

    巴扎黑2017-04-10 16:36:47

    唉,这个首先要看你随机数的范围,我给你个代码看看是不是你想要的

    $rand_array = array();
    function  get_rand_n($rand_array) {
        $rand_number = mt_rand(1,9);
        if(empty($rand_array)) {
            $rand_array[] = $rand_number;
            return get_rand_n($rand_array);
        } else {
            $count = 0;
            foreach($rand_array as $item) {
                $count += $item;
            }
            if($count<100) {
                if($count+$rand_number == 100) {
                    $rand_array[] = $rand_number;
                    return $rand_array;
                } else if($count+$rand_number < 100) {
                    $rand_array[] = $rand_number;
                    return get_rand_n($rand_array); // 回掉再次计算
                } else { // 如果得到的值大于了100
                    return get_rand_n($rand_array); // 重新获得随机数,知道为100的时候返回这个随机数数组
                }
            }
        }
    }
    $rand_array = get_rand_n($rand_array);
    var_dump($rand_array);
    

    具体结果请自测,这个取随机数有范围的。

    返事
    0
  • 阿神

    阿神2017-04-10 16:36:47

    • -我写了一个都是整数的,不知道符不符合要求。
      <?php

         $max = 100;
         $sum = 0;
         $salt = $max;
         $num = 0;
         while($sum < 100){
             $salt = $max - $sum;
             $num = rand(0,$salt);
             echo $num."<br/>";
             $sum += $num;
         }
         echo '和:'.$sum;

      ?>

    返事
    0
  • 怪我咯

    怪我咯2017-04-10 16:36:47

    我可以从另一个角度提供一点思路。 如果给你n个非整负数,要求这n个数的和为100,那么这个几个数可以取哪些值呢?假如我们有一个函数f,f返回一共有多少种解法。那么这个f可以被定义为这样: f(n, 100)。
    我们接着试一下看能不能推导出"f(n)"与"f(n-1)"之间的关系呢?
    其实如果我们假定最后一个数为0,那么剩下n-1个数的和必定为100。所以最后一个数为0时,解的个数应当为
    f(n-1, 100),最后一个数为1时,解的个数为f(n-1, 99),最后一个数为100时,解的个数为f(n-1, 0);
    那么我们就可以推导出:
    f(n, 100) = f(n-1, 100) + f(n-1, 99) + ... + f(n-1, 0)
    f(n-1, 100) = f(n-2, 100) + f(n-2, 99) + ... + f(n-2, 0)
    ...
    f(2, 100) = f(1, 100) + f(1, 99) + ... + f(1, 0)
    那么显然,f(1, k) = 1;而上面的表达式终归是由这些个1堆出来的。
    我不熟悉php,这里我写一个cpp的demo,希望能提供些帮助:

    #include <cstdio>
    #include <vector>
    
    void print(const std::vector<int>& vec) {
        for (auto i : vec) {
            printf("%d ", i);
        }
        printf("\n");
    }
    
    int collect(int k, int target, std::vector<int>& vec) {
        if (k == 1) {
            vec.push_back(target);
            print(vec);
            return 1;   
        }
    
        k--;
        int sum = 0;
        for (int i=0; i<= target; i++) {
            std::vector<int> copy(vec);
            copy.push_back(i);
            sum += collect(k, (target - i), copy);
        }
        return sum;
    }
    
    int main() {
        std::vector<int> vec = std::vector<int>();
        int result = collect(3, 5, vec);
        printf("result is %d\n", result);
        return 0;
    }
    

    以3个数加起来等于5为例(数太大膨胀的厉害)
    运行结果:
    g++ -std=c++11 -o test test.cpp
    ./test

    0 0 5
    0 1 4
    0 2 3
    0 3 2
    0 4 1
    0 5 0
    1 0 4
    1 1 3
    1 2 2
    1 3 1
    1 4 0
    2 0 3
    2 1 2
    2 2 1
    2 3 0
    3 0 2
    3 1 1
    3 2 0
    4 0 1
    4 1 0
    5 0 0
    result is 21

    返事
    0
  • PHPz

    PHPz2017-04-10 16:36:47

    我这里使用递归的方式实现了下,不过这个方式没有考虑负数的情况,不知道符合预期不

    function fn($n, $m) {
        $t = mt_rand(0, $m);
    
        if ($n <= 1) {
            echo $m , "\n";
            return $m;
        } else {
            echo $t. "\n";
            return fn($n-1, $m - $t);
        }
    }
    fn(10, 100);

    返事
    0
  • PHP中文网

    PHP中文网2017-04-10 16:36:47

    谢谢大家给的参考,不能全部采纳,请见谅!
    其实我刚才还有一个要求忘记了,就是必须不能让任何一个随机数有为0的情况!!!
    谢谢 @sPeng 的代码!在你的代码基础上,我修改一下,虽然笨一些,但是好歹是实现了!

    <?php
    function foo($n ,$max = 100){
        $array = $zero = $normal = [];
        for($i=1;$i<=$n;$i++){
            $array[] = mt_rand(0,100);
        }
        $k = $max / array_sum($array);  //求出放大系数k
        foreach($array as $key => $val){
            $value = floor($val * $k); //直接保留整数,以保证下一步的和肯定<100
            if($value<1){
                $zero[] = $value;
            }else{
                $normal[] = $value;
            }
        }
        $sum = array_sum($normal);
        $diff = $max - $sum; //这个值肯定<100
        if(!empty($zero)){ //如果有为0的值
            $count = count($zero);
            foreach($zero as $z){
                $normal[] = $diff / $count;
            }
        }else{ //随机分配给一个人
            $key = array_rand($normal);
            $normal[$key] = $normal[$key]+$diff;
        }
        print_r($zero);
        print_r($normal);
        print_r(array_sum($normal));
        unset($array,$zero,$sum,$diff);
        return $normal;
    }
    foo(10);

    返事
    0
  • 迷茫

    迷茫2017-04-10 16:36:47

    没有考虑负数和小数的情况

    function ret100($n){
        $s = 1;
        $ret = [];
        while($s<=$n){
            if($s==$n){
                array_push($ret,100-array_sum($ret));
            }else{
                array_push($ret,mt_rand(1, 100-array_sum($ret)));
            }
            if(array_sum($ret)==100){
                return $ret;
            }
            if(array_sum($ret)>100){
                return ret100($n);
            }
            $s++;
        }
    }
    
    //test
    for($i=2;$i<=100000;$i++){
        if(array_sum(ret100(mt_rand(1,30)))!=100){
            echo 'test error: '.$i;exit;
        }
    }

    返事
    0
  • キャンセル返事