将数字拆分为总和组件

时间:2011-10-16 23:42:19

标签: performance algorithm math numbers sum

是否有一种有效的算法可以将一个数字拆分为N个子部分,以便数字的总和与原始数字相加,最小值为?例如,如果我想将50分成7个子部分,并且基数最小值为2,那么我可以10,5,8,2,3,5,17(以及任何其他数量的组合)。我想将数字保持为整数,并且相对随机,但我不确定如何有效地生成总和到原始数字并且不包括低于给定最小值的数字。有什么建议吗?

编辑 - 只是复制/粘贴我的评论,整数不一定是唯一的,但我希望每次都避免所有这些整数相同(例如50分为10个相同的大小)。

9 个答案:

答案 0 :(得分:14)

这是一个算法:

  1. N除以m,其中N是您的号码,m是子章节的数量。
  2. 将结果向下舍入到最接近的值,并将该值分配给所有子部分。
  3. 在每个子部分添加一个,直到值加起来为N。此时如果N为50且m为7,则您有8,7,7,7,7,7,7
  4. 从0到m-1迭代,逐步减去2,并在-(currentValue-base)currentValue-base之间添加一个随机数。将该数字的倒数添加到其相邻存储桶中。如果您有一个奇数个桶,那么在最后一个桶上,而不是将该数字的倒数添加到其相邻桶中,以类似于上面步骤2和3的分布式方式将其添加到所有其他桶中。
  5. 性能: 第1步为O(1),第2步,第3步和第4步为O(m),因此整体为O(m)

答案 1 :(得分:5)

您可以通过从数字中减去最小次数N,生成N个子部分并添加最小值,轻松删除最小要求。在您的示例中,问题减少为将36拆分为7个整数,并且您已经给出了拆分8,3,6,0,1,3,15。

解决方案的其余部分取决于“相对随机”要求的性质。对于一些最小的随机性,考虑在0和未分裂部分之间顺序选择数字(例如,首先在0和36之间,获得8,然后在0和28之间,获得3,依此类推7次)。如果这还不够,您首先需要定义随机性。

答案 2 :(得分:4)

这是一个伪随机解决方案[注意解决方案可能有偏见,但相对随机]。

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,使用线性时间计算和填充此类列表没有问题。

<强>性能:

如上所述,步骤1是O(k)。

Step2,天真实现是O(k ^ 2),但由于你均匀分配temp-xi的结果,所以有O(k)实现,只需存储和修改delta。

Step3只是一个简单的随机播放,O(k)

整体表现: O(k)与第2步的delta实施

答案 3 :(得分:2)

好吧,我想出了一些“只是为了好玩”的东西。

它从minimum逐渐增加到number,并使用模数和随机数填充N个部分的数组。

See the jsFiddle here.

如果此数字的部分太多,它将无法正常工作。 (即number < N(N+1)/2

答案 4 :(得分:2)

以下是创建请求的数字重新分区的代码的java示例。它是递归方法,我们将问题分解为2个子问题:如果我们想要将数字分解为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);

    }

}

答案 5 :(得分:1)

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&lt; = number。

答案 6 :(得分:0)

我知道已经有很长一段时间了,但我想补充一下我的回答来帮助这里的人是我的代码使用递归

#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);
}

这里n等于10,但你可以像询问用户一样,通过使用new运算符声明a的大小!

答案 7 :(得分:0)

让我用Python编写。

假设您有50个元素可以拆分为7个框,并且您希望每个框中至少有两个元素。

N_init = 50
s = 2
m = 7

我们默认在每个框中放置s元素,因此我们留下了N个元素。

N = N_init - s*m

我们绘制m个随机数,对它们进行排序,在背面附加N.这就像在N页的书中随机插入书签。 连续书签之间的页数是随机的。 (我们确保每个盒子至少有s个元素)

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])]

完成!

答案 8 :(得分:0)

我正在做类似的事情,这就是我的想法。

您可以在每个步骤的 O(N-1)中执行此操作。首先,从每个点的最小数和最大数之间选择一个随机数。对于每个现货,最大数量是通过从剩余余额中减去(Min_Number * Remaining_Spots)来计算的。

例如:对于第一个点,您选择2到38之间的一个数字。您可以通过从50中减去(7-1)* 2来获得这个数字,即50-12 =38。

选择一个数字后,假设为19,那么下一个点的范围为2-21。即50-19-(5 * 2)= 21 ..

..依此类推。

这是代码段:

<div id="Webdevelopment">
            <div class="title">Webdevelopment</div>
            <div class="inhalt">
              <div class="inhaltbox_1 inhaltbox">
                 <ul>
                  <li>Kreatives Webdesign</li>
                  <li>Große Erfahrung mit Virtual Reality</li>
                </ul>
              </div>
              <div class="inhaltbox_2 inhaltbox">
                <ul>
                  <li>Kreatives Webdesign</li>
                  <li>Große Erfahrung mit Virtual Reality</li>
                </ul>
              </div>
            </div>
            <div class="skill">
              <table>
                <caption>skill</caption>
                <tr class="skillname">
                  <th>html</th>
                  <th>css</th>
                  <th>javascript</th>
                  <th>aframe</th>
                </tr>
                <tr class="skillicons">
                  <td>icon</td>
                  <td>icon</td>
                  <td>icon</td>
                  <td>icon</td>
                </tr>
                <tr class="sterne">
                  <td>&#9733; &#9733; &#9733;</td>
                  <td>&#9733; &#9733; &#9733;</td>
                  <td>&#9733; &#9733; &#9734;</td>
                  <td>&#9733; &#9733; &#9733;</td>
                </tr>
              </table>
            </div>
          </div>
here some css:

以下是示例输出:

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);
}

这是jsFiddle: http://jsfiddle.net/wj81kvsc/6/