生成n个随机数,其总和为m,所有数字应大于零

swa*_*il7 5 java random

我想生成9个非零随机数,其总和是250.我试过下面的代码,它给了我9个随机数,但有些数字为零.

 public void n_random()
{
  Random r = new Random();
ArrayList<Integer> load = new ArrayList<Integer>();
    int temp = 0;
    int sum = 0;
    for (int i = 1; i <= 9; i++) {
        if (!(i == 9)) {
            temp = r.nextInt(250 - sum);
            System.out.println("Temp " + (i) + "    " + temp);
            load.add(temp);
            sum += temp;

        } else {
            int last = (250 - sum);
            load.add(last);
            sum += last;
        }
    }

    System.out.println("Random arraylist " + load);
    System.out.println("Sum is "+ sum);

}
Run Code Online (Sandbox Code Playgroud)

我的错误在哪里或我应该在哪里改进我的代码或任何其他解决方案?

ass*_*ias 11

我建议使用:

temp = r.nextInt((250 - sum) / (9 - i)) + 1;
Run Code Online (Sandbox Code Playgroud)

这将确保:

  • 每个数字都是正数
  • 在达到第9个数字之前,你不会使用完整的"250补贴"

然而,结果的分布可能有偏差.

示例输出:

随机arraylist [18,28,22,19,3,53,37,49,21]

说明:

  • (250 - sum) 剩余的金额是250,所以你不想过去
  • / (9 - i) 如果您的金额已达到例如200(需要50多个)并且还有5个要去,请确保下一个随机数不超过10,为接下来的4个绘制留出一些空间
  • + 1 防止0

可能提供更好分布的替代方案是采用随机数并对它们进行缩放以得到所需的总和.示例实现:

public static void n_random(int targetSum, int numberOfDraws) {
    Random r = new Random();
    List<Integer> load = new ArrayList<>();

    //random numbers
    int sum = 0;
    for (int i = 0; i < numberOfDraws; i++) {
        int next = r.nextInt(targetSum) + 1;
        load.add(next);
        sum += next;
    }

    //scale to the desired target sum
    double scale = 1d * targetSum / sum;
    sum = 0;
    for (int i = 0; i < numberOfDraws; i++) {
        load.set(i, (int) (load.get(i) * scale));
        sum += load.get(i);
    }

    //take rounding issues into account
    while(sum++ < targetSum) {
        int i = r.nextInt(numberOfDraws);
        load.set(i, load.get(i) + 1);
    }

    System.out.println("Random arraylist " + load);
    System.out.println("Sum is "+ (sum - 1));
}
Run Code Online (Sandbox Code Playgroud)


ike*_*ami 5

生成n个随机数,其总和为m,所有数字应大于零

以下基本上是您要实现的目标.这里,它是用Perl编写的,因为我不太了解Java,但它应该很容易翻译.

use strict;
use warnings;
use feature qw( say );

use List::Util qw( shuffle );

my $m = 250;
my $n = 9;
my @nums;
while ($n--) {
   my $x = int(rand($m-$n))+1;  # Gen int in 1..($m-$n) inclusive.
   push @nums, $x;
   $m -= $x;
}

say join ', ', shuffle @nums;   # shuffle reorders if that matters.
Run Code Online (Sandbox Code Playgroud)

你的方法的问题是你会得到很多小数字.五个样本运行,数字按升序排列:

  • 1,1,1,1,2,3,6,50,185
  • 1,1,1,1,2,3,4,13,224
  • 1,1,1,1,1,3,8,11,223
  • 1,1,1,1,2,4,19,103,118
  • 2,2,9,11,11,19,19,68,109

更好的方法可能是采用N个随机数,然后对它们进行缩放,使其总和达到M.实施:

use strict;
use warnings;
use feature qw( say );

use List::Util qw( sum );

my $m = 250;
my $n = 9;

# Generate $n numbers between 0 (incl) and 1 (excl).
my @nums;
for (1..$n) {
   push @nums, rand();
}

# We subtract $n because we'll be adding one to each number later.
my $factor = ($m-$n) / sum(@nums);

for my $i (0..$#nums) {
   $nums[$i] = int($nums[$i] * $factor) + 1;
}

# Handle loss of fractional component.
my $fudge = $m - sum(@nums);
for (1..$fudge) {
   # Adds one to a random number.
   ++$nums[rand(@nums)];
}

say join('+', @nums), '=', sum(@nums);
Run Code Online (Sandbox Code Playgroud)

五个样本运行:

32+32+23+42+29+32+29+20+11=250
31+18+25+16+11+41+37+56+15=250
21+15+40+46+22+40+32+1+33=250
34+24+18+29+45+30+19+29+22=250
3+45+20+6+3+25+18+65+65=250
Run Code Online (Sandbox Code Playgroud)