所以我想知道如何计算背包问题的所有解决方案。也就是说,我有兴趣从一组最大尺寸为K的数字中找到可能的子集数。
例如,我们有一组大小为{3,2,5,6,7}的项目,最大大小为K = 13.因此解决方案为{5,6,2}和{6,7}。另一方面,有两种解决方案;我希望我的动态编程算法报告有两种可能的解决方案。
答案 0 :(得分:3)
这可以通过动态编程来完成。基本策略是构建一个记忆表d[i][j]
,该表使用汇总到j
的前i
个数字来存储组合的数量。请注意,j = 0
表示一组空数字。以下是一个示例实现:
int countCombinations(int[] numbers, int target) {
// d[i][j] = n means there are n combinations of the first j numbers summing to i.
int[][] d = new int[target + 1][numbers.length + 1];
// There is always 1 combination summing to 0, namely the empty set.
for (int j = 0; j <= numbers.length; ++j) {
d[0][j] = 1;
}
// For each total i, calculate the effect of using or omitting each number j.
for (int i = 1; i <= target; ++i) {
for (int j = 1; j <= numbers.length; ++j) {
// "First j numbers" is 1-indexed, our array is 0-indexed.
int number = numbers[j - 1];
// Initialize value to 0.
d[i][j] = 0;
// How many combinations were there before considering the jth number?
d[i][j] += d[i][j - 1];
// How many things summed to i - number?
if (i - number >= 0) {
d[i][j] += d[i - number][j - 1];
}
}
}
// Return the entry in the table storing all the number combos summing to target.
return d[target][numbers.length - 1];
}
只是添加一些Google关键字:此问题也称为将n个硬币相加而不重复到目标总和。
答案 1 :(得分:0)
这个任务有一个动态背包解决方案。在dp数组中,dp [i]存储其总和为&#34; i&#34;的子集数量。在这种情况下,你的答案是dp [K]。(对不起,缩进问题,我无法弄清楚如何使它正确:()
dp[0] = 1 ; for( int i=0; i<N ; i++ ) for( int j=K-a[i] ; j>=0 ; j-- ) dp[j+a[i]] += dp[j]
答案 2 :(得分:0)
我认为Max的算法不适用于目标为1的[0,0,1]。答案为4,但是他的算法将输出1。他的算法仅适用于正整数,因为它假定总和为0只能通过空集来实现。但是,如果数组中存在0,也可以实现。解决此问题(同时也提高空间效率)的更强大的方法是使用一维dp阵列。伪代码如下:
int[] dp = new int[target+1];
for (int num : nums) {
for (int s = target; s >= 0; s--) {
if (s >= num) { // can include num
dp[s] += dp[s-num];
} else { // cannot include num (can be omitted, here for better explanation)
dp[s] += 0;
}
}
}
return dp[target+1];
我在内部for循环中从目标回溯到0的原因是为了避免重复。考虑一下目标总和为4的示例[2,2,2]。如果从索引0进行迭代,那么当您位于dp [4]时,您将对2进行两次计数(应为[1 0 1 0 0]内循环执行一次迭代后得到[1 0 1 0 1]的值。
希望这会有所帮助。