Performance 将数字拆分为和分量

Performance 将数字拆分为和分量,performance,algorithm,math,numbers,sum,Performance,Algorithm,Math,Numbers,Sum,是否有一种有效的算法将一个数字拆分为N子部分,从而使这些数字的总和与原始数字相加,且基数最小?例如,如果我想将50分为7个子部分,并且最小基数为2,我可以执行10,5,8,2,3,5,17(以及任何其他数量的组合)。我希望将数字保持为整数,并且相对随机,但我不确定如何有效地生成与原始数字相加的数字,并且不包括低于给定最小值的数字。有什么建议吗 编辑-只是为了复制/粘贴我的评论,整数不必是唯一的,但我希望避免每次都使用相同大小的整数(例如,将50个整数拆分为10个相同大小)。通过从数字中减去最小次

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


编辑-只是为了复制/粘贴我的评论,整数不必是唯一的,但我希望避免每次都使用相同大小的整数(例如,将50个整数拆分为10个相同大小)。

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


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

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

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.
输入:
n-我们应该总结的数字
k-部件的数量
m-最小值
(1) 将n分成k个数:x1,x2,…,xk,使x1+…+xk=n,然后
可能彼此最接近[换句话说,x1=x2=…=n/k,其中
可能的情况下,端部可能在atmost+-1处变化。]
(2)对于每个数席,从i=1到k-1:
这里有一个算法:

  • N
    除以
    m
    ,其中
    N
    是您的编号,
    m
    是子部分的编号
  • 将结果向下舍入到最接近的值,并将该值分配给所有子部分
  • 在每个小节中添加一个,直到值相加为
    N
    。在这一点上,如果
    N
    是50,
    m
    是7,那么就有8,7,7,7,7,7
  • 从0迭代到
    m-1
    ,步进2,然后在
    -(currentValue base)
    currentValue base
    之间添加一个随机数。将该数字的倒数加到相邻的桶中。如果存储桶的数量为奇数,则在最后一个存储桶上,以类似于上面步骤2和步骤3的分布式方式将其添加到所有其他存储桶,而不是将该数字的倒数添加到其相邻的存储桶上
  • 性能:
    第一步是
    O(1)
    ,第二步、第三步和第四步是
    O(m)
    ,所以总的来说是
    O(m)
    ,我想出了一些“只是为了好玩”的东西

    它从
    最小值
    递增到
    数字
    ,并使用模和随机数将
    N
    节填充到数组中


    如果这个数字有太多的部分,它将不会像预期的那样工作。(即
    number

    下面是一个创建请求的数字重新分区的java代码示例。它是递归的方法,我们把问题分解成2个子问题:如果我们想把一个数字分解成n个篮子中的一个分量的总和,那么我们尝试一次考虑一个子数,并且他们中的每一个将剩余的分解中的发现委托给递归调用(N-1)筐之间的重新分配。 处理特定子编号(在for循环中)时会考虑请求的阈值

    import java.util.ArrayList;
    导入java.util.List;
    公共类测试数据{
    公共静态列表计算机分区号(整数分解、整数子数、整数阈值){
    List resultRec=新建ArrayList();
    if(子编号的编号==1){
    List resultEnd=new ArrayList();
    ArrayList酉=新的ArrayList();
    结果。添加(单一);
    酉.加法(数_到_分解);
    返回结果;
    }
    对于(int i=阈值_数;i
    
    现在,如果你想让最小数是2以外的其他值,把它改为任何值,只要提供子部分的数量*最小随机数\u所需我知道已经有很长一段时间了,但我想添加我的答案来帮助某人这里是我使用递归的代码

    #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,整数*a){
    int i;
    
    对于(i=0;i让我用Python编写它

    假设您有50个元素要拆分为7个框,并且每个框中至少要有两个

    N_init = 50
    s = 2
    m = 7
    
    默认情况下,我们在每个框中放置s个元素,因此剩下N个元素

    N = N_init - s*m
    
    我们画m个随机数,对它们进行排序,在后面加上N。这就像在一本N页的书中随机插入m个书签一样。 连续书签之间的页数是随机的。(我们有s,这样我们可以确保每个框至少有s个元素)


    完成了!

    我正在做类似的事情,下面是我的想法

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

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

    一旦你选择了一个数字,比如说19,那么下一个点的范围是2-21,即50-19-(5*2)=21

    …等等

    以下是代码片段:

    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);
    }
    
    以下是JSFIDLE:

    子集和:给定一组数字,找到一个和特定数字相加的子集。您的问题:给定一个数字,找到和它相加的对应子集。我是
    N = N_init - s*m
    
    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])]
    
    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);
    }
    
    [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]