繁体   English   中英

生成m个等于100但两个数字之差必须大于4的数字

[英]Generating m numbers that equal 100 but difference between two numbers have to be greater than 4

我正在尝试生成等于100(%)的数字 ,但所有数字彼此之间必须至少为4个数字。 因此,如果我生成4个数字,则它们必须像这样[22,28,15,35],而不能像这样[22,28,20,30],因为28-30和 22-20之间的差是小于4。

我能够组合生成数字的方法,这些数字等于如下所示。

generate (max, many) {
    this.numbers_array = []
    this.normalized_numbers_array = []
    this.sum = 0 
    for (let i = 0; i < many; i++) {
      this.numbers_array.push(Math.random())
      this.sum += this.numbers_array[i]  
    }
    this.remaining = max
    for (let i = 0; i < this.numbers_array.length; i++) {
      this.outcome= (this.numbers_array[i] / this.sum) * max
      this.normalized_numbers_array[i] = Math.floor(this.outcome)
      this.remaining -= this.normalized_numbers_array[i]
      if (i + 1 == this.numbers_array.length) {
        while (this.remaining > 0) {
          this.normalized_numbers_array[i]++
          this.remaining--
        }
      }
    }
  }  

并且工作正常。 我的下一个方法是尝试通过两个for循环和if语句相互比较归一化的数字。 然后根据数字之间的差异,我想将2%加到一个值上,并从要比较的两个数字中的另一个减去2% 然后,将它们放入要再次规范化的新数组中。

   for (let i = 0; i < this.normalized_numbers_array.length; i++) {

  for (let j = i + 1; j < this.normalized_numbers_array.length; j++) {

    if (Math.abs(this.normalized_numbers_array[i] - this.normalized_numbers_array[j]) < 5) {
        //do something
      if (this.normalized_numbers_array[i] > this.normalized_numbers_array[j]) {
        //do something
      } else if (this.normalized_numbers_array[i] <= this.normalized_numbers_array[j]) {
    //do something  
      }
    }
}

}

但是,这种方法是有缺陷的。 通过添加或构造 ,我可以使新的差异小于4。例如, [35,18,26,21]-> [35,16,26,23]更改后26与23之间的差异为3。

我的想法是要创建另一个循环,只要存在差异就行。 但是我不确定那行得通。 因此,我想知道是否存在针对此问题的更好的解决方案-也许能够从一开始生成大小不同的那些数字,而后不必更改它们。

  • 从相同范围生成四个统一的随机数
  • 缩放它们,使其总计为76(100-分隔符,请参见下文); 根据需要随机调整以解决剩余部分
  • 插入分隔符:排序,然后在第一个添加4,第二个添加8,最后一个添加12(并且不对第零进行调整)。

  • 产生[102, 387, 386, 284]
  • 规模: [102, 387, 386, 284] * 76 / (102 + 387 + 386 + 284)评估为[6, 25, 25, 18]
  • 调整:只有74,所以将1随机添加到两个元素: [6, 25, 26, 19]
  • 排序: [6, 19, 25, 26]
  • 插入分隔符: [6, 23, 33, 38]

总计为100,保证至少相隔4,[EDIT]循环很少(以确保不被零除),并且对分布的任意干扰也很少。 出于好奇,它是这样的:

 function f() { let q, s; while (!s) { q = Array.from({length: 4}, () => Math.random()); s = q.reduce((a, e) => a + e); } q.forEach((e, i, q) => q[i] = (e * 76 / s)|0); s = q.reduce((a, e) => a + e); while (s < 76) { q[(Math.random() * 4)|0]++; s++; } q.sort((a, b) => a - b); q.forEach((e, i, q) => q[i] += i * 4); return q; } const N = 100000; function draw() { const labels = ["#0", "#1", "#2", "#3", "Any"]; const colours = ["red", "orange", "green", "blue", "black"]; const data = Array.from({length:5}, (e, i) => ({ label: labels[i], borderColor: colours[i], backgroundColor: i == 4 ? "rgba(0, 0, 0, 0.1)" : "rgba(0, 0, 0, 0)", pointRadius: 0, data: Array.from({length:100}, (e, i) => ({ x: i, y: 0 })) })); for (let s = 0; s < N; s++) { const q = f(); q.forEach((e, i) => { data[i].data[e].y++; data[4].data[e].y++; }); } const ctx = document.querySelector('canvas').getContext('2d'); const myChart = new Chart(ctx, { type: 'line', data: { datasets: data }, options: { maintainAspectRatio: false, animation: false, legend: { position: 'right' }, scales: { yAxes: [{ ticks: { beginAtZero: true } }], xAxes: [{ type: 'linear', ticks: { beginAtZero: true, max: 100 } }] } } }); }; draw(); document.querySelector('canvas').addEventListener('dblclick', draw); 
 <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js"></script> <canvas width="400" height="180"/> 

 <!DOCTYPE html> <html> <head> </head> <style> .HideX{ display:none; }; </style> <body> <input type="text" id="QQ"> <input type="text" id="QQ2"> <script> function isEmpty(map) { for(var key in map) { if (map.hasOwnProperty(key)) { return false; } } return true; } function GetRandom(St,Range){ return Math.floor((Math.random() * Range) + St); } function Pick4(){ var BigPool={}; var ResultX=[]; //Generate [1,100] for(var i=1;i<=100;i++){ BigPool[i.toString()]=i; } var Remain=100; var Last=100; for(var j=0;j<3;j++){ if(isEmpty(BigPool)){//Althoght impossible but add this exception return Pick4(); } var Pick=GetRandom(1,Remain); if(BigPool.hasOwnProperty(Pick.toString())){ delete BigPool[Pick.toString()];//Remove Pick ResultX.push(Pick); Remain-=Pick; for(var i=Remain+1;i<=Last;i++){ if(BigPool.hasOwnProperty(i.toString())){ delete BigPool[i.toString()];//Remove above remain } } Last=Remain; }else{ j--; continue; } for(var i=-3;i<=3;i++){//Remove [Pick-3,Pick+3] if(BigPool.hasOwnProperty((Pick+i).toString())){ delete BigPool[(Pick+i).toString()];//Remove [Pick-3,Pick+3] } } } if(BigPool.hasOwnProperty(Remain.toString())){ ResultX.push(Remain); }else{ return Pick4(); } return ResultX; } var G=Pick4(); document.getElementById("QQ").value = G; document.getElementById("QQ2").value = G.reduce((a, b) => a + b, 0); </script> </body> </html> 

这是简单的答案

一种小蛮力方法。 运行后,从数组中获取随机结果。

 function get4() { function iter(temp, sum) { var i, s, t; for (i = 0; i <= max; i++) { s = sum + i; if (s > max) return; t = temp.concat(i); if (t.length === 4) { if (s === max) result.push(t.map((v, i) => v + 4 * i)); continue; } iter(t, s); } } var result = [], max = 76; iter([], 0); return result; } var result = get4(); console.log(result.length); console.log(result.map(a => a.join(' '))); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

这是统计驱动的问题解决方法,可能有助于从不同角度查看问题。 我们将使用多项式分布 ,其自然性质是sum 始终等于n (在您的情况下为100)。 一个人可以这样玩概率,即采样数之间的差异很可能大于4。因为多项式的平均值为n * p i ,所以我们将概率相距较远。 采样后,对数组进行排序并检查差异。 如果它们很接近,我们将拒绝该样本,并要求再次抽奖。 我使用https://github.com/jacobmenick/sampling代码进行多项式采样,还有其他库。

代码,节点12.1,Windows 10 x64

var multinom = SJS.Multinomial(100, [.02, .17, .33, .48]); // far away spacing of means n*p_i

q = multinom.draw().sort((a, b) => a - b); // sorted sample from multinomial
m = [] // array of pairwise differences, with first element removed
for (var k = 0; k < q.length - 1; ++k) {
    var curr = q[k];
    var next = q[k + 1];
    m.push(next - curr);
}
reject = m.some(el => el < 4); // check for pairwise distance, if true reject sample and get another one
s = q.reduce((a, b) => a + b, 0); // check for sum, should be always 100
console.log(q);
console.log(m);
console.log(reject);
console.log(s);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM