php求100个数字的和,用程序生成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($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."

";

$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#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; i<= target; i++) {

std::vectorcopy(vec);

copy.push_back(i);

sum += collect(k, (target - i), copy);

}

return sum;

}

int main() {

std::vectorvec = std::vector();

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 $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($s100){

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)类似于快速排序的方法,一定有一个数大而一个数小

(2)通过类似于高斯当年解决1+。。。+100的想法`#coding=utf-8

import random

def foo(n, m):

mid = m * 2 // n

duo = m - mid * n // 2

numbers = [random.randint(0,mid) for _ in range(n // 2)]

numbers1 = [mid-i for i in numbers]

numbers.extend(numbers1)

numbers[0] = numbers[0] + duo

if(n%2):

numbers.append(mid//2)

return [i for i in numbers]

if __name__ == '__main__':

res = foo(9,100)

print('10个数为:', res)

print('它们的和为:', sum(res))`

微信红包 算法

很简单,用个循环,采用概率随机数的方法

rand(1,100) 随机出来一个,然后通过减法算出下次的区间比如

rand(1,87) 一直循环,最后一直到剩下的数字作为n次的数字

来个JavaScript的:每次生成一个余下范围的// n是个数,v是总和

function lessANumber(n, v) {

var i,

s = 0,

r = [],

x = v;

for (i = 1; i < n; i++) {

x = Math.random() * x;

r.push(x);

s += x;

x = v - s;

}

r.push(x);

return r;

}

这是到目前为止题主的说明,在题主自己回答的答案中,提供了另外一个条件,不能有数为零。

所以没有任何说明这个数是什么数,从题主的回答来看也不能是负数。那么我们记题主用来生成这种数的基本的随机数产生函数为函数fn。

1, 使用函数fn,生成N - 1个数大于0,小于100的数,如果相同则舍弃该数,再生产一个

2, 将这N - 1个函数升序排列,在首尾添加0与100,形成N + 1个数的数列A(因为数不能是负数)

3, 计算数列A相邻元素的差值并存入集合S

则集合S即为所需的数集。如果每个数有最值限制,比如大于a,小于b。已经可以转化再使用上述思路解决。

你想弄红包算法?

假定要求生成的数是整数,如果不要求整数,处理更简单些,还去掉一些限制。

代码如下:public class Test {

public static void main(String[] args) {

try {

Test.createN(1, 100);

Test.createN(3, 100);

Test.createN(5, 100);

Test.createN(10, 100);

Test.createN(99, 100);

Test.createN(100, 100);

Test.createN(101, 100);

} catch (Exception ex) {

Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);

}

}

public static void createN(int n, int t) throws Exception {

if(n>t) {

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

s += numbers[i];

}

System.out.println("The sum is "+s);

}

}

想了一下,我是这样实现的function numsNone(n){

var nums = [],

result = 0;

for(var i=0; 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的结束循环

这么简单的问题,我都不屑于解决~且看你们如何答

相关标签:php

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值