Java代码:生成n个随机数,它们的和为x?

3
我正在制作一个音乐生成程序,需要从0.125、0.25和0.5中选择一组x个随机数,使它们的和为1。我无法想出一种既能保留随机元素又能整洁地完成此操作的方法。
谢谢!

2
好听的音乐有着一定的模式(我个人的看法)。也许你想要一个比“随机”更复杂的计划。 - Atreys
1
是的,谢谢!我正在做这个,我正在制作随机图案,然后通过一些变化来重复它们。 - neutrino
5个回答

5

只需列举所有可能总和为1的组合(并不是很多),并将它们存储在数组中。 然后只需为该数组计算一个随机索引号以获取随机组合。


3

有9种组合可以加起来得到1。如果您完全不关心顺序,那么只需在1和9之间随机选择一个数字即可。

  • {.5,.5}
  • {.5,.25,.25}
  • {.5,.25,.125,.125}
  • {.5,.125,.125,.125,.125}
  • {.25,.25,.25,.25}
  • {.25,.25,.25,.125,.125}
  • {.25,.25,.125,.125,.125,.125}
  • {.25,.125,.125,.125,.125,.125,.125}
  • {.125,.125,.125,.125,.125,.125,.125,.125}

如果您关心顺序,则需要排列。集合{.5,.25,.25}有3!个排列:

  • .5, .25, .25
  • .5, .25, .25
  • .25, .5, .25
  • .25, .5, .25
  • .25, .25, .5
  • .25, .25, .5

然而,您可能只想计算唯一的排列。

  • .5, .25, .25
  • .25, .5, .25
  • .25, .25, .5

对于每个集合,您可以使用像这样的算法来生成唯一的排列。 http://www.kerrywong.com/2006/04/14/generating-unique-permutations-programmatically/

一旦您知道所有排列(或唯一排列),就可以使用随机数选择其中一个排列。


啊,太棒了,这是一个有趣的看法! - neutrino

1

如果您关心以后扩展值,您可能需要考虑更动态的方法。避免硬编码值和逻辑。以下解决方案可能有所帮助。在下面的示例中,最大值1是可配置的,可以用于相加的值集也是可配置的。加载列表(从文件或输入)然后程序就可以运行了。这假设在运行之前已将列表按最低到最高值排序。

public class MusicGeneration{

    private List<Double> values = new ArrayList<Double>();
    Random rand = new Random();
    private double max_value = 0;

    public MusicGeneration() {
        max_value = 10;
        values.add(0.125);
        values.add(0.25);
        values.add(0.5);
        values.add(0.75);
    }

    private void createMusic() {
        double total = 0;

        while (total < max_value) {
            int i = rand.nextInt(maxChoice(total));
            System.out.println("Picked :: " + values.get(i));

            total += values.get(i);
            System.out.println("Total :: " + total);
        }
    }

    private int maxChoice(double total) {
        int size = values.size() - 1;

        while (size > 0) {
            if ((max_value - total) >= values.get(size)) {
                System.out.println("Returning " + (size + 1));
                return (size + 1);
            }
            size--; 
        }
        return 1;
    }

    public static void main(String args[]) {
        MusicGeneration play = new MusicGeneration();
        play.createMusic();
    }
}

是的,绝对希望未来版本能有这样动态的功能。谢谢! - neutrino

0

一种迭代解决方案,如果可能性太大,则可以轻松地进行泛化。
只需检查每个步骤可以合法的数字,并根据其生成下一个数字。

Java 代码:

static Random random = new Random();
public static double getRandom(double[] l) {
    int i = random.nextInt(l.length);
    return l[i];
}
public static List<Double> getRandNums() {
    List<Double> l = new LinkedList<Double>();
    double x = 1;
    double[] arr1 = { 0.125, 0.25, 0.5 };
    double[] arr2 = { 0.125, 0.25 };
    double[] arr3 = { 0.125 };
    double r;
    while (x > 0) { 
        if (x >= 0.5) {
            r = getRandom(arr1);
        } else if (x >= 0.25) {
            r = getRandom(arr2);
        } else { 
            r = getRandom(arr3);
        }
        l.add(r);
        x -= r;
    }
    return l;
}

0
创建一个数组,存储这三个双精度浮点数:0.125、0.25、0.5。然后生成一个1-3之间的数字,使用它作为数组的索引,并将结果与您目前为止的总和相加,与1进行比较。如果小于1,则将它们相加并继续执行。如果等于1,则停止程序。如果大于1,则生成另一个随机索引。

如果大于目标值,您应该从数组中删除返回的数字,因为它显然太大了,所以没有必要再尝试使用这个数字。 - JB Nizet
MicSim所发布的解决方案将需要更多的存储空间,但可以减少运行时间。你自己决定吧。 - lettucemode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接