我正在尝试找到 ALL 一组n个数字的子集,其总和为m。例如,如果我有集(10,20,30,40,40,50,80)
和m = 90
,则子集为(10,80)
,(20,30,40)
和(40,50)
。我有一些代码,可以使用像......这样的小案例来查找。
M[i, j] = max(M[i − 1, j], M[i − 1, j − A[i])
然后使用...回溯。
if (M[n][m]!=0)
{
for ( i = n; i >= 1; i --)
if (M[i - 1][j]!=M[i][j])
{
printf ("Use item %d = %d\n", i, A[i]);
j -= A[i];
}
}
但是当我尝试更大的测试用例时,它不会返回所有子集。任何帮助都将非常感激。
答案 0 :(得分:1)
所有正数都允许修剪,这大大降低了复杂性(虽然我不知道平均多少)。对于大型集合,您可能需要更精确的算法,但这里有:
nums
;例如,nums = {10,20,30,40,40,50,80} cum
;这将是cum = {10,30,60,100,140,190,270} 现在(C-ish伪代码)
void parts(target, index, set){ // assuming we only want to print the sets out
if (target == 0){
print out set;
return;
}
while(index >= 0 && nums[index] > target) --index; // skip too large numbers
if (index < 0 || cum[index] < target) return; // done, all numbers too large or total too small
for(; index >= 0 && cum[index] >= target; --index){ // we can stop when the total sum is too small
add nums[index] to set;
parts(target - nums[index], index-1, set);
remove nums[index] from set;
// if no duplicate sets are desired, skip duplicates, for the example,
// (40,50) would be created twice without skipping:
// while(index > 0 && nums[index-1] == nums[index]) --index;
}
}
答案 1 :(得分:0)
/* first we sort M with a quicksort, for instance,
whose an efficient implementation can be easily found on the web. */
M = quicksort(M);
/* we don't consider elements greater than m
so we compute the index of the greatest element to consider */
int max = n - 1;
for (; max > 0 && M[max] > m; max--);
int total = 1 << (max + 1);
for (int i = 0; i < total; i++)
{
/* In this loop we'll go through all the possible subsets of M */
int sum = 0;
for (int k=0; k<n; k++)
{
if ((1 << k) & i)
{
s += M[k];
/* if s is greater than m no need to go further */
if (s > m)
{
break;
}
}
}
if (sum == m)
{
/* Here we have found a successful subset so
we can output it however we want.
It is composed of all the elements used
to build s in the loop above */
}
}