84669 Lernen von Personen
152542 Lernen von Personen
20005 Lernen von Personen
5487 Lernen von Personen
7821 Lernen von Personen
359900 Lernen von Personen
3350 Lernen von Personen
180660 Lernen von Personen
48569 Lernen von Personen
18603 Lernen von Personen
40936 Lernen von Personen
1549 Lernen von Personen
1183 Lernen von Personen
32909 Lernen von Personen
想破了头,也没想出来怎么算!!!
业精于勤,荒于嬉;行成于思,毁于随。
1, 先生成n个随机数2, 对这n个数的和m3, 用100除以m, 求出放大系数k4, 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($count<100) { if($count+$rand_number == 100) { $rand_array[] = $rand_number; return $rand_array; } else if($count+$rand_number < 100) { $rand_array[] = $rand_number; return get_rand_n($rand_array); // 回掉再次计算 } else { // 如果得到的值大于了100 return get_rand_n($rand_array); // 重新获得随机数,知道为100的时候返回这个随机数数组 } } } } $rand_array = get_rand_n($rand_array); var_dump($rand_array);
具体结果请自测,这个取随机数有范围的。
-我写了一个都是整数的,不知道符不符合要求。 <?php
$max = 100; $sum = 0; $salt = $max; $num = 0; while($sum < 100){ $salt = $max - $sum; $num = rand(0,$salt); echo $num."<br/>"; $sum += $num; } echo '和:'.$sum;
?>
我可以从另一个角度提供一点思路。 如果给你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 <cstdio> #include <vector> void print(const std::vector<int>& vec) { for (auto i : vec) { printf("%d ", i); } printf("\n"); } int collect(int k, int target, std::vector<int>& vec) { if (k == 1) { vec.push_back(target); print(vec); return 1; } k--; int sum = 0; for (int i=0; i<= target; i++) { std::vector<int> copy(vec); copy.push_back(i); sum += collect(k, (target - i), copy); } return sum; } int main() { std::vector<int> vec = std::vector<int>(); int result = collect(3, 5, vec); printf("result is %d\n", result); return 0; }
以3个数加起来等于5为例(数太大膨胀的厉害)运行结果:g++ -std=c++11 -o test test.cpp ./test
0 0 5 0 1 4 0 2 3 0 3 2 0 4 1 0 5 0 1 0 4 1 1 3 1 2 2 1 3 1 1 4 0 2 0 3 2 1 2 2 2 1 2 3 0 3 0 2 3 1 1 3 2 0 4 0 1 4 1 0 5 0 0 result is 21
我这里使用递归的方式实现了下,不过这个方式没有考虑负数的情况,不知道符合预期不
function fn($n, $m) { $t = mt_rand(0, $m); if ($n <= 1) { echo $m , "\n"; return $m; } else { echo $t. "\n"; return fn($n-1, $m - $t); } } fn(10, 100);
谢谢大家给的参考,不能全部采纳,请见谅!其实我刚才还有一个要求忘记了,就是必须不能让任何一个随机数有为0的情况!!!谢谢 @sPeng 的代码!在你的代码基础上,我修改一下,虽然笨一些,但是好歹是实现了!
<?php function foo($n ,$max = 100){ $array = $zero = $normal = []; for($i=1;$i<=$n;$i++){ $array[] = mt_rand(0,100); } $k = $max / array_sum($array); //求出放大系数k foreach($array as $key => $val){ $value = floor($val * $k); //直接保留整数,以保证下一步的和肯定<100 if($value<1){ $zero[] = $value; }else{ $normal[] = $value; } } $sum = array_sum($normal); $diff = $max - $sum; //这个值肯定<100 if(!empty($zero)){ //如果有为0的值 $count = count($zero); foreach($zero as $z){ $normal[] = $diff / $count; } }else{ //随机分配给一个人 $key = array_rand($normal); $normal[$key] = $normal[$key]+$diff; } print_r($zero); print_r($normal); print_r(array_sum($normal)); unset($array,$zero,$sum,$diff); return $normal; } foo(10);
没有考虑负数和小数的情况
function ret100($n){ $s = 1; $ret = []; while($s<=$n){ if($s==$n){ array_push($ret,100-array_sum($ret)); }else{ array_push($ret,mt_rand(1, 100-array_sum($ret))); } if(array_sum($ret)==100){ return $ret; } if(array_sum($ret)>100){ return ret100($n); } $s++; } } //test for($i=2;$i<=100000;$i++){ if(array_sum(ret100(mt_rand(1,30)))!=100){ echo 'test error: '.$i;exit; } }
1, 先生成n个随机数
2, 对这n个数的和m
3, 用100除以m, 求出放大系数k
4, n个随机数分别乘以k
这个方法是有精度损失的, 我测试一般在99.9 - 100.1之间
放个python3的代码
输出:
不妨换个角度看这个问题,会简单很多:把100个1随机分配给N个数。所以循环100次,每次随机选中第1到N间的某个数,给它加1。
如果要求不能有数为0,则一开始每个数初始化为1,然后只循环90次即可。
(1,100)生成第一个数n1
(1,100-n1)生成第二个n2
...
最后一个是100-(n1+n2...)
假设是n个数。
给你另一种思路,先有100这个数据池子,从里面每次随机取出一个数字,池子减少相应的数字,递归这个过程。
当需要跳出递归,最后一次的数据取出全部。
整个过程类似微信红包。唯一注意的时候,需要判断剩余的池子里能不能最少满足你的n。
唉,这个首先要看你随机数的范围,我给你个代码看看是不是你想要的
具体结果请自测,这个取随机数有范围的。
-我写了一个都是整数的,不知道符不符合要求。
<?php
?>
我可以从另一个角度提供一点思路。 如果给你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,希望能提供些帮助:
以3个数加起来等于5为例(数太大膨胀的厉害)
运行结果:
g++ -std=c++11 -o test test.cpp
./test
0 0 5
0 1 4
0 2 3
0 3 2
0 4 1
0 5 0
1 0 4
1 1 3
1 2 2
1 3 1
1 4 0
2 0 3
2 1 2
2 2 1
2 3 0
3 0 2
3 1 1
3 2 0
4 0 1
4 1 0
5 0 0
result is 21
我这里使用递归的方式实现了下,不过这个方式没有考虑负数的情况,不知道符合预期不
谢谢大家给的参考,不能全部采纳,请见谅!
其实我刚才还有一个要求忘记了,就是必须不能让任何一个随机数有为0的情况!!!
谢谢 @sPeng 的代码!在你的代码基础上,我修改一下,虽然笨一些,但是好歹是实现了!
没有考虑负数和小数的情况