Is there an efficient algorithm to split up a number into N
subsections so that the sum of the numbers adds up to the original, with a base minimum? For example, if
You can easily remove the requirement of a minimum by subtracting minimum times N from the number, generating the N subsections and adding the minimum. In your example, the problem reduces to splitting 36 into 7 integers, and you have given the split 8,3,6,0,1,3,15.
The rest of the solution depends on the nature of the "relatively random" requirement. For some minimal randomness, consider choosing numbers sequentially between 0 and the unsplitted part (e.g. between 0 and 36 first, gaining 8, then between 0 and 28, gaining 3, and so on 7 times). If that doesn't suffice, you'll need to define randomness first.
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)
Now if you want minimum number to be something else besides 2, change it to any value provided number_of_subsections * min_random_number_desired <= number.
Let me write it in Python.
Let's say that you have 50 elements to split into 7 boxes and you want at least two inside each of them.
N_init = 50
s = 2
m = 7
We put s elements by default in each box so we are left with N elements.
N = N_init - s*m
We draw m random numbers, sort them, append N on the back. This is like inserting randomly m bookmarks in a book of N pages. The number of pages between consecutive bookmarks is random. (We had s so that we are sure that each box has at least s elements)
a = sorted([random.randint(0,N+1) for i in range(m)])
a.append(N)
result = [j-i+s for(i,j) in zip(a[0:m],a[1:m+1])]
Done!
I know there`s been a long time but i would like to add my answer to help someone here is my code using recursion
#include <stdio.h>
#include <stdlib.h>
void print(int n, int * a) {
int i ;
for (i = 0; i <= n; i++) {
printf("%d", a[i]);
i < n ? printf(" + ") : printf("");
}
printf("\n");
}
void integerPartition(int n, int * a, int level){
int first;
int i;
if (n < 1) return ;
a[level] = n;
print(level, a);
first = (level == 0) ? 1 : a[level-1];
for(i = first; i <= n / 2; i++){
a[level] = i;
integerPartition(n - i, a, level + 1);
}
}
int main(int argc, char ** argv){
int n = 10;
int * a = (int * ) malloc(sizeof(int) * n);
integerPartition (n, a, 0);
return(0);
}
Here n is equal to 10 but u could make it like asking the user,declare the size of a by using the new operator !
I was working on something similar and here is what I came up with.
You can do this in O(N-1) using some calculations at each step. You begin by picking a random number between the minimum number and max number for each spot. For each spot, max number is calculated by subtracting (Min_Number * Remaining_Spots) from the Remaining Balance.
For example: for the first spot you pick a number between 2 and 38. You get this by subtracting (7-1)*2 from 50. i.e. 50 - 12 = 38.
Once you pick a number, let's say 19, then for the next spot the range is 2-21. i.e. 50-19-(5*2) = 21..
..and so on.
Here is the code snippet:
function splitNumIntoXRandomComponents(num, x, min_num) {
var components = [];
var count = 1;
var cumulative = 0;
var balance = num;
for (var i = 0; i<x-1; i++) {
//max num for this spot
var max_num = balance - ((x-count)*min_num);
//to avoid big numbers in the beginning and min numbers at the end
if (Math.random() > 0.5){ //0.5 can be tuned to your liking
max_num = Math.floor(max_num / 2) + min_num;
}
//generate the number for the spot at 'count'
var c = Math.floor(Math.random()*(max_num-min_num+1)+min_num);
//adjust balances
cumulative += c;
balance -= c;
count++;
//store this number
components.push(c);
}
//push remaining balance into the last spot
components.push(balance);
//print numbers
console.log(components);
}
for (var i=0; i<10; i++) {
splitNumIntoXRandomComponents(50, 7, 2);
}
Here is the sample output:
[34, 2, 4, 3, 3, 2, 2]
[14, 12, 8, 8, 4, 2, 2]
[7, 4, 26, 5, 2, 3, 3]
[8, 2, 16, 4, 4, 9, 7]
[20, 8, 4, 4, 7, 4, 3]
[3, 34, 4, 2, 2, 2, 3]
[10, 5, 15, 2, 7, 5, 6]
[6, 3, 10, 4, 10, 3, 14]
[31, 4, 2, 3, 5, 2, 3]
[7, 5, 2, 9, 9, 2, 16]
Here is the jsFiddle: http://jsfiddle.net/wj81kvsc/6/
here is a pseudo random solution [note that solution might be biased, but will be relatively random].
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.
regarding part 1, for example: for n=50, k = 7
, you will set:
x1=x2=...=x6=7,x7=8
, no problem to compute and populate such a list with linear time.
Performance:
As said, step1 is O(k).
Step2, with naive implementation is O(k^2), but since you distribute result of temp-xi
evenly, there is O(k) implementation, with just storing and modifying delta.
Step3 is just a simple shuffle, O(k)
Overall performance: O(k) with delta implemntation of step2