Split number into sum components

后端 未结 9 2157
-上瘾入骨i
-上瘾入骨i 2021-02-12 18:07

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

相关标签:
9条回答
  • 2021-02-12 18:27

    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.

    0 讨论(0)
  • 2021-02-12 18:32
    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.

    0 讨论(0)
  • 2021-02-12 18:35

    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!

    0 讨论(0)
  • 2021-02-12 18:36

    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 !

    0 讨论(0)
  • 2021-02-12 18:39

    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/

    0 讨论(0)
  • 2021-02-12 18:41

    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

    0 讨论(0)
提交回复
热议问题