我的问题可以简化如下。
有s
个分区,每个分区内都有k
个数字
组合由每个箱子中的一个数字组成,因此总共有k^s
个可能的组合
组合的得分是它包含的s
数字的总和。
如何找到得分低于某个值r
的所有组合?
现在我正在做的是,
1)对每个箱子中的数字进行排序
2)从优先级队列开始,该队列仅包含每个bin中最小数字的组合
3)从队列中弹出一个组合,将该组合的s
个孩子添加到队列中。 (组合中的孩子是将一个组合的数字替换为同一个区域中的下一个更大的数字,因此组合中有s
个孩子。)
4)重复3)直到弹出的组合大于r
。
假设我们发现n
组合小于r
,则此算法的时间复杂度为O(nlog(s-1)n + sklogk)
。
当然这个算法并不是最优的。例如,我们可以从已知的下限开始,而不是从最小的组合开始。我有一种感觉,动态编程也可以在这里应用,但我没有弄清楚如何去做。
欢迎任何建议,谢谢。
答案 0 :(得分:1)
对列进行排序后,您可以使用递归算法,该算法使用下一个bin中的元素扩展部分选择,直到选择完成(或超出总和限制)。完成后,将其添加到结果中。通过回溯,所有有效选择都会添加到结果中。
这是一些伪代码。最后一个参数是输入和输出:
function combinations(int[][] bins, int r, int[] selection, int[][] result):
if r < 0 then:
return
if selection.length >= bins.length then:
result.add(selection)
return
bin = bins[selection.length]
for (i = 0; i < bin.length; i++):
# Concatenate the i-th value from the bin to a new selection array
combinations(bins, r - bin[i], selection + bin[i], result)
以下是JavaScript中的实现:
function sortBins(bins) {
for (bin of bins) {
bin.sort(function (a,b) { return a-b; });
}
}
function combinations(bins, r, selection, result) {
if (r < 0) return result; // nothing added to result
if (selection.length >= bins.length) return result.concat([selection]);
var bin = bins[selection.length];
for (var i = 0; i < bin.length; i++)
result = combinations(bins, r - bin[i], selection.concat([bin[i]]), result);
return result;
}
// Test data:
var r = 13;
var bins = [
[5, 2, 3],
[9, 4, 1],
[6, 5, 7]
];
// Get solution:
sortBins(bins);
var result = combinations(bins, r, [], []);
// Output results:
console.log(result);
&#13;