【问题标题】:Improving this subset sum algorithm for a sequential range without using recursion在不使用递归的情况下改进此子集和算法的顺序范围
【发布时间】:2015-07-08 05:15:27
【问题描述】:

给定一个minmax,我想使用指定数量的bins 查找该范围内所有与给定total 相加的数字组合(重复使用数字是可以的)。 # 箱数将接近但不超过 32,因此如果可以选择按位计算,那就太棒了。

例如:

input:
min = 1
max = 4
total = 9
bins = 4

output:
1,1,3,4
1,2,2,4
1,2,3,3
2,2,2,3

我蹩脚、低效的解决方案:

function arrSum(arr) {
  var sum = 0;
  for (var i = 0; i < arr.length; i++) {
    sum += arr[i];
  }
  return sum;
}

function incrementComboArr(arr, maxNum) {
  var i = arr.length - 1;
  while (i >= 0) {
    if (++arr[i] > maxNum) {
      i--;
    } else {
      for (var j = i + 1; j < arr.length; j++) {
        arr[j] = arr[i];
      }
      break;
    }
  }
  return i === -1;
}

getSetCombos = function (minNum, maxNum, target, bins) {
  var iters = 0;
  var solutions = [];
  var arr = [];
  var i;
  for (i = 0; i < bins; i++) {
    arr[i] = minNum;
  }
  while (true) {
    iters++;
    var sum = arrSum(arr);
    if (sum === target) {
      solutions.push(arr.slice());
    }
    if (incrementComboArr(arr, maxNum)) break;
  }
  console.log(iters);
  return solutions;
};

我的解决方案的问题在于,即使当前迭代与目标值之间的增量是确定性的,它也会增加 1。而且,它不知道什么时候停止。 (我可以通过执行if arr[0] &gt; ~~(total/bins) 之类的操作来确定最后一个可行的解决方案,但这似乎很不稳定。鉴于该系列是一个序列,我知道必须有一些我没有利用的模式,但我想不出代码/想法/讲义都欢迎!


结果

在将两个答案都转换为 ES5(欢迎编辑)后,第一个解决方案的时钟时间约为 5 毫秒,第二个解决方案(递归)的时钟时间约为 500 毫秒。我会在一天后将此标记为已回答。

这是我用于每个的代码:

//Code translated from Spektre
subsetSum = function (minNum, maxNum, target, bins) {
  var start = new Date();
  var solutions = [];
  var arr = [];
  var i;
  var s;
  var loop = true;
  for (i = 0; i < bins; i++) {
    arr[i] = minNum;
  }
  s = minNum * bins;
  while (loop) {
    if (s === target) {
      solutions.push(arr.slice());
    }
    for (i = bins;;) {
      i--;
      arr[i]++;
      s++;
      for (var j = i + 1; j < bins; j++) {
        s+= arr[i]-arr[j];
        arr[j]=arr[i];
      }
      if ((s<=target)&&(arr[i]<=maxNum)) break;
      if (!i) {
        loop = false;
        break;
      }
      s+=maxNum-arr[i];
      arr[i]=maxNum;
    }
  }
  return new Date() - start;
};


//Code translated from karthik
subsetSumRecursive = function(minNum, maxNum, target, bins) {
  var start = new Date();
  var solutions = [];
  var arr= [], i;
  var totalBins = bins;
  for (i = 0; i < bins; i++) {
    arr[i] = minNum;
  }
  target -= minNum * bins;
  countWays(target, bins, arr, 0);
  return new Date() - start;
  function countWays(target, binsLeft, arr) {
    if (binsLeft === 1) {
      arr[totalBins-1] += target;
      if (arr[totalBins-1] <= maxNum) {
        solutions.push(arr.slice());
      }
      return;
    }
    if (target === 0 && arr[totalBins-binsLeft] <= maxNum) {
      solutions.push(arr.slice());
      return;
    }
    var binsCovered = 0;
    if (target >= binsLeft) {
      var newArr = arr.slice();
      while (binsCovered < binsLeft) {
        newArr[totalBins - binsCovered -1]++;
        binsCovered++;
      }
      countWays(target - binsLeft, binsLeft, newArr);
    }
    countWays(target, binsLeft-1, arr);
  }
};

subsetSum(1,4,100,32);
subsetSumRecursive(1,4,100,32);

【问题讨论】:

  • 我能想到的唯一其他方法是将其建模为约束满足问题,最小值/最大值是域,将变量的数量分类并总计约束。根据输入,CSP 可能比迭代更有效,也可能不更有效,而且它本质上也是递归的。
  • 你在说这样的事情吗? stackoverflow.com/a/30870577/3155110 如果是这样,那么对于较小的集合来说,它的速度会慢 2 倍,尽管不确定大 O 时间。如果没有,请给我一个链接,我会深入研究它。
  • 不,你可以只在维基 CSP 上阅读并阅读,但它是带有回溯的递归...... 1,2 -> 1,1,3 -> 1,2,1 直到 3,3,3 然后在你达到总数时打印出来。
  • @MattK 垃圾箱是否相同?我的意思是如果总数是4,那么1,2,11,1,2 被认为是不同的或相同的
  • @MattK 你有什么限制,比如每个垃圾箱至少应该有1 吗?

标签: javascript algorithm math subset-sum


【解决方案1】:

在 C++ 中我会这样做:

//---------------------------------------------------------------------------
AnsiString subset_sum(int min,int max,int sum,int N)
    {
    AnsiString txt="",lin; int cnt=0;   // output text and number of subsets fond
    int i,s,a[32];                      // iterator,actual sum,actual permutation

    // init nested for
    for (i=0;i<N;i++) a[i]=min; s=min*N;
    // nested for
    for (bool _loop=true;_loop;)
        {
        // if correct sum remember it to txt and update cnt
        if (s==sum)
            {
            for (lin="",i=0;i<N;i++) lin+=AnsiString(a[i])+" "; txt+=lin+"\r\n";
            cnt++;
            }
        // nested for step lequeal
        for (i=N;;)
            {
            i--; a[i]++; s++;
            if ((s<=sum)&&(a[i]<=max)) break;
            if (!i) { _loop=false; break; }
            s-=a[i]; a[i]=min; s+=a[i];
            }
        }

    txt+=AnsiString(cnt)+" subsets found\r\n";
    return txt;
    }
//---------------------------------------------------------------------------
  • 它基于nested for in C++
  • 并添加了忽略更高总和的条件
  • 可以通过计算最后一个a[N-1]=sum-s来加速
  • 对于 32 个垃圾箱,这也太慢了...
  • 但比您的方法更快

[edit1] 删除(位置随机排列)重复项

//---------------------------------------------------------------------------
AnsiString subset_sum(int min,int max,int sum,int N)
    {
    AnsiString txt="",lin; int cnt=0;   // output text and number of subsets fond
    int i,j,s,a[32];                        // iterator,actual sum,actual permutation
    // init nested for
    for (i=0;i<N;i++) a[i]=min; s=min*N;
    // nested for
    for (bool _loop=true;_loop;)
        {
        // if correct sum remember it to txt and update cnt
        if (s==sum)
            {
            for (lin="",i=0;i<N;i++) lin+=AnsiString(a[i])+" "; txt+=lin+"\r\n";
            cnt++;
            }
        // nested for step lequeal
        for (i=N;;)
            {
            i--; a[i]++; s++;
            for (j=i+1;j<N;j++) { s+=a[i]-a[j]; a[j]=a[i]; }
            if ((s<=sum)&&(a[i]<=max)) break;
            if (!i) { _loop=false; break; }
            s+=max-a[i]; a[i]=max;
            }
        }

    txt+=AnsiString(cnt)+" subsets found\r\n";
    return txt;
    }
//---------------------------------------------------------------------------

现在增量是这样的:

1,1,1,1
1,1,1,2
1,1,1,3
1,1,1,4
1,1,2,2
1,1,2,3
1,1,2,4
1,1,3,3
...

subset_sum(1,4,100,32); 的速度现在非常快,只需几个 5.4 [ms]

结果如下:

1 1 1 1 1 1 1 1 1 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 1 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 1 2 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 1 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 2 2 2 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 2 2 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 1 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 2 2 2 2 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 2 2 2 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 2 2 2 2 2 2 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 2 2 2 2 2 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 2 2 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 2 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 2 2 2 2 2 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 2 2 2 2 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 2 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 2 2 2 2 2 2 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 2 2 2 2 2 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 
1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 2 2 2 2 2 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 
1 1 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 
1 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 
1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 2 2 2 2 2 2 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 2 2 2 2 2 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 
1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 
1 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 
1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 
1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 
2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 
2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 
2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 
2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 
2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 
80 subsets found

【讨论】:

  • 我喜欢这样摆脱数组求和函数的方式,但是没有机制可以确保组合已经尝试过,所以它仍然非常昂贵。例如,这会尝试1,2,2,4,然后在最后检查4,2,2,1。 (也就是说,如果我翻译正确的话:jsbin.com/potilofewo/edit?js,console
  • @MattK hmm 对我来说没有发生这种情况......可能是a[i] 的某种排序将是一个很好的解决方案,因此对于任何排列将a[i]&lt;=a[i-1] 对于任何i 如果不忽略迭代...这会大大加快速度,我只在总和高于总和时才忽略
  • @MattK 已尝试对我之前的评论进行编码,结果请参见 [edit1]
  • 问题已更新以包含您的代码的结果。我可能会在发货前添加一个上限,但它肯定比我的要好,谢谢!
【解决方案2】:

它可能看起来很复杂,但一旦你明白为什么按升序排列可以避免重复,这很容易:)

我尝试过您的解决方案,但无法完全理解。

我将从递归开始,我知道您不想要递归解决方案,但这是一个动态编程递归,因此很容易将其转换为迭代解决方案。

你不能给total命名,所以说你必须在k礼品盒中分配n巧克力,所以礼品盒的数量=k和总数=n,为了简单起见arr= {min,min+1, .....max} 是一个数组。

现在避免重复的关键是按升序分配巧克力(降序也可以)。所以你 7 块巧克力,我在第一个盒子里放了 2 块巧克力,我会在第二个盒子里至少放 2。为什么?这有助于避免重复。

         you will have to use base cases like n>0 , number of items < max           

         now onwards TCL = totalChocholatesLeft & TBL  = totalBinsLeft

         So S(TCL,TBL) =  S(TCL-TBL,TBL) + S(TCL,TBL-1);

         you have to call the above expression starting with S(n-(k*min), k)

         Why? because all boxes need at least one item so first put `min` each box. 
         Now you are left with only n-(k*min) chocolates.

就是这样!这就是DP递归。

它是如何工作的?

        So in order to remove repetitions we are maintaning the ascending order.
        What is the easiest way to maintain the ascending order ? 

如果你在第 i 个盒子里放 1 块巧克力,在它前面的所有盒子里放 1 块 i+1, i++2 .....k。 所以把巧克力放在礼盒里后,你有两种选择:

您要继续使用当前框:

                S(TCL-TBL,TBL) covers this

或者移动下一个盒子,不要再考虑这个盒子了

                S(TCL,TBL-1) covers this.

如果您想更容易地维护最大约束,您可以传递一个List&lt;Integer&gt;,它表示每个 bin 中的元素数量。 因此,在调用递归之前,您必须将每个 bin 中的元素数量增加 1。这将使 TC:O(N^2K)

这是一个有效的代码:我刚刚编写了递归函数,你可以使用一个 output[n][k] 数组并将其转换为 DP,只要有函数调用(countWays(x,y))只需检查 countWays[x][y] 是否为 -1 然后仅递归调用函数,否则仅返回值

    static int totalWays = 0;
    static int totalbins=32,bins=32;
    static int min=1,max=4;
    static int[][] countWays;
    public static void main(String[] args) throws IOException {
        int[] chocs = new int[bins];
        int total = 100;
        for(int i=0;i<bins;i++){
            chocs[i] =min;
        }
        countWays= new int[total+1][bins+1];

        for(int i=1;i<total+1;i++){
            for(int j=1;j<bins+1;j++){
                countWays[i][j]= -1;
            }
        }
        total = total - (min*bins);
        countWays[total][bins] =countWays(total,bins,chocs);
        System.out.println("Total ways:" + totalWays);
        System.out.println("Total ways:" + countWays[total][bins]);

    }

    private static int countWays(int total, int binsLeft, int[] chocs) {
        if(binsLeft == 1){
            chocs[totalbins-1]= chocs[totalbins-1] +total;
            if(chocs[totalbins-1] <= max) {
                doStuff(chocs);
                return 1;
            }
            countWays[total][1]=0;
            return 0;
        }
        if(total == 0 ){
            if(chocs[totalbins-binsLeft] <= max) {
                doStuff(chocs);
                return 1;
            }else{
                return 0;
            }
        }

        int binsCovered =0;
        int x=0,y=0;
        if(total >= binsLeft) {
            int[] newArray = new int[totalbins];
            for (int i = 0; i < totalbins; i++) {
                newArray[i] = chocs[i];
            }
            while (binsCovered < binsLeft) {
                newArray[totalbins - binsCovered - 1]++;
                binsCovered++;
            }
            x = countWays(total - binsLeft, binsLeft, newArray);

        }
        y = countWays(total, binsLeft-1, chocs);
        countWays[total][binsLeft] = x+y;
        return countWays[total][binsLeft];
    }

    public static void doStuff(int[] chocs) {
        totalWays++;
//        for(int i=0;i<totalbins;i++)
//        {
//           // System.out.print(chocs[i] + " ");
//        }
//        //System.out.println();
    }

【讨论】:

  • 我很难想象这一点,但我认为它遵循我已经采用的相同概念,但如果我错了,请纠正我。例如,k=4, n=9, minChocolatesPerBox = 1, maxChocolatesPerBox = 4。如果我当前的递归位于1,2,4,4,则递归@ idx 4 将结束,递归@ idx 3 将结束并且我的递归@ idx 2 会将2 增加到3。这将给我1,3,3,3,因为以下巧克力盒必须是>= 当前。如果我离题了,请给我看一个试验迭代的示例列表,这样我就可以得到模式。干杯
  • 到达1,2,4,4 点后,如果您不能再放巧克力,这意味着您在第 4 个盒子。你只会终止,你永远不会回到2 并增加它。 1,3,3,3 来自 1,2,2,2 时的不同方式,并且您正在考虑第二个框 如果您选择继续使用第二个框,它将变为 1,3,3,3 但如果您想留下第二个框,那么您的配置仍然是1,2,2,2,但您的框变为 3。在下一次递归中,它变为 1,2,3,3 和后来的 1,2,4,4
  • 一旦离开一个盒子,你就再也回不去了。这是问题的核心,它可以避免您收到重复订单。
  • 在调试器中花了我大约 30 分钟的时间来理解这是在做什么,但我终于明白了,谢谢!我更新了我的问题以包含 JS 翻译以进行比较。不幸的是,递归比另一个慢大约 100 倍。如果我在翻译中搞砸了一些东西以使其变慢,请随时告诉我。干杯
  • @MattK 不,请参阅我的答案,就在代码之前(我用粗体写的部分):您应该使用二维数组来存储计算结果,这样您就不需要计算他们一次又一次。递归一次又一次地重复计算相同的结果,这就是为什么它很慢。试着去做,然后它在 O(KN) 中运行,这要快得多。到家后我会写下来并更新答案。
猜你喜欢
  • 2020-02-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 2016-02-01
相关资源
最近更新 更多