Разделить число на суммарные компоненты
Есть ли эффективный алгоритм для разбиения числа на подразделы N
так, чтобы сумма чисел складывалась до оригинала с базовым минимумом? Например, если я хочу разделить 50 на 7 подразделов и иметь базовый минимум 2, я мог бы сделать 10,5,8,2,3,5,17
(а также любое другое количество комбинаций). Я хотел бы сохранить числа как целые числа и относительно случайные, но я не уверен, как эффективно генерировать числа, которые суммируются с оригиналом и не включают числа, меньшие, чем данный минимум. Любые предложения?
EDIT. Просто чтобы скопировать/вставить мой комментарий, целые числа не обязательно должны быть уникальными, но я хочу избежать одинаковых размеров для всех из них (например, 50 разделенных на 10 одинаковых размеров) каждый раз.
Ответы
Ответ 1
Здесь алгоритм:
- Разделите
N
на m
, где N
- ваш номер, а m
- количество подразделов.
- Завершите результат до его ближайшего значения и присвойте это значение всем подразделам.
- Добавьте один в каждый подраздел, пока значения не будут добавлены к
N
. В этот момент, если N
было 50, а m
равно 7, у вас было бы 8, 7, 7, 7, 7, 7, 7
- Перейдите от 1 до N, сделав шаг 2 и добавьте случайное число между
-(N-base)
и N-base
. Добавьте инверсию этого числа в соседний ведро. Если у вас есть нечетное количество ведер, то в последнем ковше вместо добавления инверсии этого числа в соседний ведро добавьте его ко всем другим ковшим распределенным образом, аналогичным шагам 2 и 3. выше.
Производительность:
Шаг 1 равен O(1)
, шаги 2, 3 и 4 составляют O(m)
, поэтому в целом это O(m)
.
Ответ 2
Вы можете легко удалить требование минимума, вычитая минимальное время N из числа, создавая N подразделов и добавляя минимум. В вашем примере проблема сводится к разбиению 36 на 7 целых чисел, и вы дали разделить 8,3,6,0,1,3,15.
Остальная часть решения зависит от характера "относительно случайного" требования. Для некоторой минимальной случайности рассмотрите выбор чисел последовательно между 0 и незарасчетной частью (например, между 0 и 36 сначала, набрав 8, затем между 0 и 28, получив 3 и так далее 7 раз). Если этого недостаточно, сначала вам нужно определить случайность.
Ответ 3
вот псевдослучайное решение [обратите внимание, что решение может быть предвзятым, но будет относительно случайным).
input:
n - the number we should sum up to
k - the number of 'parts'
m - minimum
(1) split n into k numbers: x1,x2,...,xk such that x1+...+xk = n, and the numbers
are closest possible to each other [in other words, x1 = x2 = ... = n/k where
possible, the end might vary at atmost +-1.]
(2) for each number xi from i=1 to k-1:
temp <- rand(m,xi)
spread x - temp evenly among xi+1,...,xk
xi <- temp
(3) shuffle the resulting list.
относительно части 1, например: для n=50, k = 7
вы установите:
x1=x2=...=x6=7,x7=8
, нет проблем для вычисления и заполнения такого списка линейным временем.
Производительность:
Как сказано, step1 равен O (k).
Шаг 2 с наивной реализацией - O (k ^ 2), но поскольку вы равномерно распределяете результат temp-xi
, существует реализация O (k) с простое хранение и изменение delta.
Шаг 3 - просто простая перетасовка, O (k)
Общая производительность: O (k) с дельта-выполнением шага 2
Ответ 4
Ну, я придумал что-то "просто для удовольствия".
Он идет постепенно от minimum
до number
и заполняет массив секциями N
, используя по модулю и случайным образом.
Смотрите здесь jsFiddle.
Он не будет работать, как ожидалось, если для этого числа слишком много разделов. (т.е. number < N(N+1)/2
)
Ответ 5
Вот пример Java-кода, создающий запрошенный передел чисел. Это рекурсивный подход, мы разлагаем задачу на две подзадачи: если мы хотим разложить число в сумму компонентов среди n корзин, то мы попытаемся рассмотреть поднабор за раз, и для каждого из них делегировать обнаружение оставшегося разложения до рекурсивного вызова для перераспределения среди (n-1) корзин.
Запрашиваемый порог считается при обработке определенного поднабора (в цикле for).
import java.util.ArrayList;
import java.util.List;
public class TestFigures {
public static List<List<Integer>> computeRepartitionNumber(int number_to_decompose, int number_of_subnumbers, int threshold_number) {
List<List<Integer>> resultRec = new ArrayList<>();
if (number_of_subnumbers == 1) {
List<List<Integer>> resultEnd = new ArrayList<>();
ArrayList<Integer> unitary = new ArrayList<>();
resultEnd.add(unitary);
unitary.add(number_to_decompose);
return resultEnd;
}
for (int i = threshold_number; i <= number_to_decompose-threshold_number; i++) {
int remain = number_to_decompose - i;
List<List<Integer>> partialRec = computeRepartitionNumber(remain, number_of_subnumbers - 1, threshold_number);
for(List<Integer> subList : partialRec){
subList.add(i);
}
resultRec.addAll(partialRec);
}
return resultRec;
}
public static void main(String[] args) {
List<List<Integer>> superlist = computeRepartitionNumber(5, 2, 1);
System.out.println(superlist.size());
System.out.println(superlist);
}
}
Ответ 6
import random
def split_given_number_into_n_random_numbers(number, number_of_subsections, min_random_number_desired = 0):
cumulative_sum_of_random_numbers = 0
current_subsection = 1
max_random_number = int(number/number_of_subsections)
if min_random_number_desired > max_random_number:
print("ERROR: Cannot have min number as {} and split {} in {} subsections".format(min_random_number_desired,
number, number_of_subsections))
return False
while (True):
random_number = random.randint(min_random_number_desired, max_random_number)
print("Random number {} = {}".format(current_subsection, random_number))
cumulative_sum_of_random_numbers += random_number
# print("Cumulative sum {}".format(sum_of_num))
number -= random_number
current_subsection += 1
if current_subsection == number_of_subsections:
random_number = number
print("Random number {} = {}".format(current_subsection, random_number))
cumulative_sum_of_random_numbers += random_number
break
print("Final cumulative sum of random numbers = {}".format(cumulative_sum_of_random_numbers))
return True
if __name__ == '__main__':
split_given_number_into_n_random_numbers(50, 7, 2)
Теперь, если вы хотите, чтобы минимальное число было чем-то другим, кроме 2, измените его на любое значение, указанное number_of_subsections * min_random_number_desired <= number.