随机生成m个和为n的数

方法一: 转换为将 n 随机分给m个数

这个问题的难点在于:如何保证m个随机数 和为 n。所以不妨转换思路为:将 n 随机分给 m 个数。eg:如果要生成 9 个和为 100 的随机数,且随机数为 int。那不妨将 100拆分成 100 个 1 然后随机分给 9 个数。以下是具体讨论

1. 随机生成 m 个和为 n 的数, 生成的数为 int


/*
        1. 定义一个数组,数组长度为m. 
        2. 由于int数组的初值为0, 所以只需要随机从数组里取出数,然后加1
				3. 随机生成 [m, n]的随机数  m + (int)(Math.random() * (n - m + 1))
*/

/**
     * @description 随机生成 m个和为n的数, 生成的数为int
     * @author HelloWorld
     * @create 2022/1/9 10:26
     * @param m
     * @param n
     * @return void
     */
    private void getMArrayInt(int m, int n){
        int[] results = new int[m];
        int unit = 1;
        for (int i = 0; i < n / unit; i++) {
            int random = (int)(Math.random() * m);
            results[random] += unit;
        }
        System.out.println(results);
    }

2. 假如随机生成的数有条件要求,最小值不得小于m

    /**
     * @description 随机生成 m 个和为 n 的数,生成的数为 int 且最小值不得小于 x
     * @author HelloWorld
     * @create 2022/1/9 10:26
     * @param m
     * @param n
     * @return void
     */
    private void getMArrayIntConditions(int m, int n) {
        // 不妨先将 最小值设为 3
        int min = 3;
        int unit = 1;
        int c;
        int[] results = new int[m];
        for (int i = 0; i < m; i++) {
            results[i] = min;
        }
        /*
            现在需要考虑循环的次数
            由于已经分配出了 m * min 个数了,相当于 此时的 n = n - m * min
         */
        for (int i = 0; i < (n - m * min); i++) {
            int random = (int)(Math.random() * m);
            results[random] += unit;
        }
        System.out.println(results);
    }

3. 那如果再加一个条件呢,生成的数要在 min 到 max之间

    /**
     * @description 随机生成 m 个和为 n 的数,生成的数为 int 且范围在 [min, max]
     * @author HelloWorld
     * @create 2022/1/9 11:07
     * @param m
     * @param n
     * @return void
     */
    public void getMArrayIntConditions1(int m, int n) {
        // 同样 不妨先设 min = 5; max = 70
        int min = 5, max = 70, unit = 1;
        int[] results = new int[m];
        for (int i = 0; i < m; i++) {
            results[i] = min;
        }

        for (int i = 0; i < (n - m * min); i++) {
            int random;
            while (true) {
                random = (int)(Math.random() * m);
                if (results[random] <= max - unit){
                    break;
                }
            }
            results[random] += unit;
        }
        System.out.println(results);

    }

4. 随机生成 m个和为n的数, 生成的数精确到小数点后两位 且最小值大于 n的 1% 最大值不能超过 n的 90%

   /**
     * @description 随机生成 m个和为n的数, 生成的数精确到小数点后两位 且最小值大于 n的 1% 最大值不能超过 n的 90%
     * @author HelloWorld
     * @create 2022/1/9 10:25
     * @param m
     * @param n
     * @return void
     */
    private void getMArray(int m, int n){
        BigDecimal unit = new BigDecimal("0.01");
        BigDecimal[] results = new BigDecimal[m];
        BigDecimal min = new BigDecimal(n * 0.01);
        BigDecimal max = new BigDecimal(n * 0.9);
        // 最小值大于 n 的 1%
        for (int i = 0; i < m; i++) {
            results[i] = min.add(unit);
        }
        for (int i = 0; i < (int)(n / Double.valueOf(unit.toString())); i++) {
            int random ;
            // 最大值不超过 max
            while (true) {
                random = (int) (Math.random() * m);
                if (max.compareTo(results[random]) > 0) {
                    break;
                }
            }
            results[random] = results[random].add(unit);
        }

        System.out.println(results);
    }

方法二:先随机生成 m 个数,然后等比例放大或缩小

例如 要生成10个和为100的随机数,可以先生成10个随机数,然后将这10个数相加得到 count,然后将每个随机数 * (100 / count);但是这样会存在精度问题,不在此讨论了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值