茶后一道算术题

本人最近经常脑抽,容易产生幻想! 求治疗!

这道题并非来自于 产品需求, 而是在sf看帖子的时候意淫的时候产生的!

需求:

写一算法 ,满足以下三个条件即可!
条件一:5个数 和值为100;
条件二:5个数 的每个数值 波动范围 为 16 - 24;
条件三:每种组合出现的概率必须为 1/3951 ,也就是 万分之3.5 ( 下面做说明 );

条件三说明 : 穷举出 所有 组合

var sum = 0 , q ,w ,r ,t,y ;
for (q = 16; q < 25 ; q ++ ) {
    for (w = 16; w < 25 ; w ++ ) {
        for (r = 16; r < 25 ; r ++ ) {
            for (t = 16; t < 25 ; t ++ ) {
                for (y = 16; y < 25 ; y ++ ) {
                    if((q + w + r + t + y) == 100){
                        sum ++;
                    }
                }
            }
        }
    }
}
console.log(sum);  // 总共有 3951 组合情况, 那么每一种出现的概率应该是 1/3951;

我自己写了个 函数,下面直接贴代码:(代码很原始,请轻喷!)

function ran() {
    var a, b, c, d, e, average, sum = 0, str2 = "", arr = [];
    a = parseInt(Math.random() * 9) + 16;
    b = parseInt(Math.random() * 9) + 16;

    average = (100 - (a + b ))/ 3;
    if ((average - 16) > (24 - average )) {
        c = parseInt(Math.random() * parseInt(24 - average) *2 ) + parseInt(average - parseInt(24 - average));
    }else {
        c = parseInt(Math.random() * parseInt(average - 16) *2 ) + parseInt(average - parseInt(average - 16));
    }

    average = (100 - (a + b + c))/ 2;
    if ((average - 16) > (24 - average )) {
        d = parseInt(Math.random() * parseInt(24 - average) *2 ) + parseInt(average - parseInt(24 - average));
    }else {
        d = parseInt(Math.random() * parseInt(average - 16) *2 ) + parseInt(average - parseInt(average - 16));
    }
    e = 100 - a - b - c - d;
}

基本思路: 先随机两个,然后再根据前面生成的两个数,改变后面的数的 波动区间。
然而检查中发现:问题那么多!!!

1、用5000000次循环检查 所以可能出现的 组合数 为2248, 也就是说少了接近2000中可能;
2、循环1000000次,检查其中 两三种 出现的概率 
    (20 ,20 ,20,20 ,20)出现的概率波动比较大在170-210之间,
    (20 ,19 ,21,20 ,20)出现的概率 在230-270之间 ,这个还概率还是比较合理,
    (24 ,19 ,21,20 ,16)出现的概率 为 0,这个.....
    

各位路过的大神,就当 茶后 笑谈,给鄙人点亮 知识之光,赐予我 高明的 思路吧,阿门!

阅读 3.9k
5 个回答

先把几千种可能性放到数组里
再shift 得出概率可控
时间复杂度o(0)

__

多次随机必会压缩解空间
t1大神专门说过

检查的方法是
检查1 :所有组合的总数目

  var str2 = "", arr = []; 

  str2 = "" + a + b + c + d + e;
  if (arr.indexOf(str) == -1) {
       arr.push(str2);
  }
  console.log(arr.length); // 循环 5000000次 打印值为2248

检查2 : 其中一种出现的概率数

if (a == 20 && b == 19 && c ==21 && d ==20 && e ==20){
   sum ++;
}
console.log(sum) // 循环1000000次 打印值在 170 -210 之间波动

貌似你说的是「波动均分算法」。你说的条件三我当时也有考虑实现,不过没有想到好的思路可以实现这一点,希望有大神可以提供个思路

感觉概率要均衡的话,不能是每个数一次。数的概率均衡了。最后的结果的概率就不均衡。数的概率应该要不均衡。比如符合条件结果里第一个数20出现了10次,17出现了5次(ps:乱猜的。表示想法)
代码大概的结构应该是这样


var ran_num = function(sum, count) {
    var next_num = Math.random();
    switch(count) {
        case 1:
            return sum;
        case 2:
            return 16 + parseInt((sum - 16 * 2) * next_num);
        case 3: 
            // TODO
        case 4: 
            // TODO
        case 5: 
            // TODO
    }
    return next_num;
};
var run = function() {
    var created_nums = [], sum = 0, num;
    for (var i = 0; i < 5; i++) {
        num = ran_num(100 - sum, 5 - i);
        sum += num;
        created_nums.push(num);
    }
    return created_nums.join('-');
};
var arr = []
var q ,w ,r ,t ,y
for (q = 16; q < 25 ; q ++ ) {
    for (w = 16; w < 25 ; w ++ ) {
        for (r = 16; r < 25 ; r ++ ) {
            for (t = 16; t < 25 ; t ++ ) {
                for (y = 16; y < 25 ; y ++ ) {
                    if((q + w + r + t + y) == 100){
                        arr.push([q, w, r, t, y])
                    }
                }
            }
        }
    }
}
const index = Math.floor(Math.random() * 3951)
return arr[index]

(逃

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题