方法一: 转换为将 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);但是这样会存在精度问题,不在此讨论了