![](/img/trans.png)
[英]Generate 20 random numbers between 0-100, and then display all odd numbers and those that are greater or equal to 50
[英]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。
我的想法是要创建另一个循环,只要存在差异就行。 但是我不确定那行得通。 因此,我想知道是否存在针对此问题的更好的解决方案-也许能够从一开始就生成大小不同的那些数字,而后不必更改它们。
例
[102, 387, 386, 284]
[102, 387, 386, 284] * 76 / (102 + 387 + 386 + 284)
评估为[6, 25, 25, 18]
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.