sub Solve
{
my ($goal, $elements) = @_;
# For extra speed, you can remove this next line
# if @$elements is guaranteed to be already sorted:
$elements = [ sort { $a <=> $b } @$elements ];
my (@results, $RecursiveSolve, $nextValue);
$RecursiveSolve = sub {
my ($currentGoal, $included, $index) = @_;
for ( ; $index < @$elements; ++$index) {
$nextValue = $elements->[$index];
# Since elements are sorted, there's no point in trying a
# non-final element unless it's less than goal/2:
if ($currentGoal > 2 * $nextValue) {
$RecursiveSolve->($currentGoal - $nextValue,
[ @$included, $nextValue ],
$index + 1);
} else {
push @results, [ @$included, $nextValue ]
if $currentGoal == $nextValue;
return if $nextValue >= $currentGoal;
}
} # end for
}; # end $RecursiveSolve
$RecursiveSolve->($goal, [], 0);
undef $RecursiveSolve; # Avoid memory leak from circular reference
return @results;
} # end Solve
my @results = Solve(7, [2,3,4,7]);
print "@$_\n" for @results;
这开始是你链接的问题中C#版本的直接翻译,但我稍微简化了一下(现在更加简化了),并删除了一些不必要的变量分配,基于元素列表进行了一些优化,并重新排列条件以使其稍微更有效率。
我现在还添加了另一个重要的优化。当考虑是否尝试使用不能完成总和的元素时,如果该元素大于或等于当前目标的一半,则没有意义。(我们添加的下一个数字将更大。)根据您尝试的集合,这可以更快地终止。(您也可以尝试添加下一个元素而不是乘以2,但然后您必须担心是否会超出列表的末尾。)
{2,3,4,6,9}
和x==11
,那么您不能有{{2,3,6},{2,9}}
,因为重复使用了2
。或者,通过“集合”您是指“子集”? - vol7ron{2,3,3,3}
不是一个有效的答案,因为你每个子集只能使用3一次。 - cjm