Maison > Article > développement back-end > 用程序生成n个随机数,要求n个数的和等于100
想破了头,也没想出来怎么算!!!
想破了头,也没想出来怎么算!!!
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
不妨换个角度看这个问题,会简单很多:把100个1随机分配给N个数。所以循环100次,每次随机选中第1到N间的某个数,给它加1。
如果要求不能有数为0,则一开始每个数初始化为1,然后只循环90次即可。
(1,100)生成第一个数n1
(1,100-n1)生成第二个n2
...
最后一个是100-(n1+n2...)
假设是n个数。
给你另一种思路,先有100这个数据池子,从里面每次随机取出一个数字,池子减少相应的数字,递归这个过程。
当需要跳出递归,最后一次的数据取出全部。
整个过程类似微信红包。唯一注意的时候,需要判断剩余的池子里能不能最少满足你的n。
唉,这个首先要看你随机数的范围,我给你个代码看看是不是你想要的
$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($counta8945d550b2244d61e1636ffd448ede2
我可以从另一个角度提供一点思路。 如果给你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#includevoid print(const std::vector& vec) { for (auto i : vec) { printf("%d ", i); } printf("\n"); } int collect(int k, int target, std::vector& vec) { if (k == 1) { vec.push_back(target); print(vec); return 1; } k--; int sum = 0; for (int i=0; i0adb17c16015544a6011ea845f1d7723t) { throw new Exception("Error parameter n("+n+") > t("+t+")"); } int total = t; int[] numbers = new int[n]; for(int i=0; ii; k--) { numbers[k] = 1; } break; } } numbers[n-1] = total; // check System.out.println(Arrays.toString(numbers)); int s = 0; for(int i=0; i<n; i++) { s += numbers[i]; } System.out.println("The sum is "+s); } }
想了一下,我是这样实现的
function numsNone(n){ var nums = [], result = 0; for(var i=0; i<n; i++){ nums.push(Math.floor((Math.random() * 100))); result += nums[i]; } if(result === 100){ console.log(nums); return nums; }else{ return numsNone(n); } } numsNone(3);
sPeng的答案最好,其他说每次取随机数后把随机数范围减小的算法在分布上不够随机
// 用程序生成n个随机数,要求n个数的和等于100 function ssum($num,$sum) { $numArr = []; $top = $sum-$num+1; while(true){ $tmp = rand(1,$top); $numArr[] = $tmp; $sum = $sum-$tmp; $top = $sum; $num--; if($num == 1){ $numArr[] = $top; break; } } return $numArr; }
好好捋捋逻辑。。。并不难
如果n个数都是整数就更简单了。。。
直接随机生成99个数,最后一个数用100减去前面99个数的总和
使用递归,不断改变随机数的范围。
暴力大法好,无限循环生成随机数,如果和大于100则清空记录和的变量的值,一直到有等于100的结束循环
这么简单的问题,我都不屑于解决~且看你们如何答