11.06.2018, 23:27
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
массив, распределение суммы как можно более равномерно
Вариант решения ниже, не очень оптимальный, подскажите любое другое решение.
var input = [5,10,0,12], //массив лимита каждой ячейки
total = 7, // сумма которую надо распределить равномерно
output = [];// результат распределения
//total = 7 => output = [2,2,0,3]
//total = 20 => output = [5,7,0,8]
//total = 40 => output = [5,10,0,12]
function fn(input, total, output) {
for (var i = 0; total; i = ++i % input.length) {
output[i] = output[i] || 0;
if (output[i] + 1 > input[i]) continue;
output[i]++;
total--
}
return output
};
console.log(fn(input, total, output))//[3, 2, 0, 2]
|
|
12.06.2018, 00:26
|
|
Профессор
|
|
Регистрация: 01.12.2016
Сообщений: 3,650
|
|
Ровнее только с плавающей точкой.
|
|
12.06.2018, 00:34
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
j0hnik,
все числа целые, требуется оптимизация, желательно 1 проход по массиву или 2 - 3, а не как сейчас, пока сумма по 1 не уменьшится до конца.
|
|
12.06.2018, 00:39
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
j0hnik,
что-то типа
output[i] = Math.floor(total/input.length)
|
|
12.06.2018, 00:44
|
|
Профессор
|
|
Регистрация: 15.01.2015
Сообщений: 622
|
|
function fn(input, total) {
const output = [];
const order = input.map((_, index) => index);
const sortedOrder = order.sort((a, b) => input[b] - input[a]);
const mustCheckIndexes = [];
for (let i = 0; i < sortedOrder.length; i++) {
const sortedIndex = sortedOrder[i];
if (i === 0) {
mustCheckIndexes.push(sortedIndex);
} else if (input[sortedIndex] === input[sortedOrder[i - 1]]) mustCheckIndexes.push(sortedIndex);
else break;
}
for (let i = 0; total; i = ++i % input.length) {
let breakCycle = false;
for (const mustCheckIndex of mustCheckIndexes) {
if (output[mustCheckIndex] === input[mustCheckIndex]) breakCycle = true;
else breakCycle = false;
}
if (breakCycle) break;
const currIndex = sortedOrder[i];
output[currIndex] = output[currIndex] || 0;
if (output[currIndex] + 1 > input[currIndex]) {
continue;
}
output[currIndex]++;
total--
}
return output
};
|
|
12.06.2018, 00:48
|
|
Профессор
|
|
Регистрация: 01.12.2016
Сообщений: 3,650
|
|
рони,
придумал разве что проверку добавить
if(input.reduce((c,e)=> e+c) <= total) return output = [...input];
больше ничего.
|
|
12.06.2018, 01:43
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
EmperioAf,
спасибо, попробую разобраться
j0hnik,
Rise,
спасибо, да я в курсе когда total больше суммы -- выше был минимальный пример.
|
|
12.06.2018, 02:28
|
|
Профессор
|
|
Регистрация: 19.01.2012
Сообщений: 505
|
|
Сообщение от рони
|
j0hnik,
что-то типа
output[i] = Math.floor(total/input.length)
|
Так и делай, только floor лучше заменить на ceil.
var input = [5,10,0,12], //массив лимита каждой ячейки
total = 7, // сумма которую надо распределить равномерно
output = [];// результат распределения
//total = 7 => output = [2,2,0,3]
//total = 20 => output = [5,7,0,8]
//total = 40 => output = [5,10,0,12]
function allocate(input, total, output) {
var rest = total; //остаток
var quotient = Math.ceil(total/input.length); //частное
var waste_count = 0; //счётчик превышений
for( var i = 0; i < input.length; i++ ){
output[i] = output[i] || 0;
output[i] += quotient;
rest -= quotient;
if( output[i] > input[i] ) {
var waste = output[i] - input[i];
output[i] -= waste;
rest += waste;
waste_count++;
}
if( rest <= 0 ) {
output[i] += rest;
break;
}
}
//console.log(waste_count, rest, quotient);
if( waste_count == input.length ) return output;
if( rest > 0 ) return allocate(input, rest, output);
return output;
}
console.log( allocate(input, 7, []) );
console.log( allocate(input, 20, []) );
console.log( allocate(input, 40, []) );
|
|
12.06.2018, 02:31
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
Белый шум,
спасибо!
|
|
12.06.2018, 02:37
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,109
|
|
равномерное распределение суммы
вариант на котором остановился, если есть замечания напишите, всем откликнушимся большое спасибо!!!
<script>
function allocate(input, total) {
const output = [];
const length = input.length;
const order = input.map((value, index) => ({value,index}));
const sortedOrder = order.sort((a, b) => a.value - b.value);
for (let i = 0; i < length; i++) {
let {value,index} = sortedOrder[i];
let num = Math.floor(total/(length - i))
if(num > value) num = value;
total -= num;
output[index] = num
}
return output
};
let input = [5,10,0,12];
for (let total = 0; total < 41; total++) {
let output = allocate(input, total)
document.write(`${total}=>${output}<br>`)
}
</script>
Последний раз редактировалось рони, 12.06.2018 в 08:39.
Причина: добавлено const length
|
|
|
|