My internet was down for a while, so I amused myself by optimizing my code a little. To be specific I only look at pairs of partitions with a positive difference, I moved the "break out early" checks out of the inner loop, and I switched from using hashes to arrays.

sub find_best_partition { my @numbers = sort {abs($b) <=> abs($a) or $a <=> $b} @_; # First we're going to find a "pretty good" partition. If we can, # we'll find a partition that finishes off this way. That will # usually let the full algorithm abort early. my @in_partition; my $current_remaining = 0; for my $n (@numbers) { if ($current_remaining < 0) { if ($n > 0) { push @in_partition, 1; $current_remaining += $n; } else { push @in_partition, 0; $current_remaining -= $n; } } else { if ($n > 0) { push @in_partition, 0; $current_remaining -= $n; } else { push @in_partition, 1; $current_remaining += $n; } } } my $known_solution = $current_remaining; # Cheat, we're going to find out the extremes. my @max_sum_of_previous = 0; my $sum = 0; for my $n (@numbers) { $sum += abs($n); push @max_sum_of_previous, $sum; } # We're going to try to find partitions that add up to each # possible number that can be added up to. my $old; my $new = [ [[], []] ]; my $i = -1; my $answer; for my $n (@numbers) { $old = $new; $new = []; $i++; my $upper = $#$old; # Skip values too big to lead to an improvement. if ( $upper > $sum - $max_sum_of_previous[$i] + abs($known_solution) ) { $upper = $sum - $max_sum_of_previous[$i] + abs($known_solution); } if ($current_remaining > 0) { if ($old->[$current_remaining]) { my ($p1, $p2) = @{ $old->[$current_remaining] }; $answer = [$p2, $p1]; last; } } elsif ($old->[-$current_remaining]) { $answer = $old->[-$current_remaining]; last; } for my $key (0..$upper) { my $value = $old->[$key] or next; my ($p1, $p2) = @$value; if ($key + $n < 0) { $new->[-$key - $n] ||= [$p2, [$n, $p1]]; } else { $new->[$key + $n] ||= [[$n, $p1], $p2]; } if ($key - $n < 0) { $new->[$n - $key] ||= [[$n, $p2], $p1]; } else { $new->[$key - $n] ||= [$p1, [$n, $p2]]; } } # Adjust $current_remaining for the fact we're skipping # the $i'th element. if ($in_partition[$i]) { $current_remaining -= $n; } else { $current_remaining += $n; } } if (not $answer) { # Do not include any of the original partition. $i = @numbers; for my $j (0..$#$new) { if ($new->[$j]) { $answer = $new->[$j]; last; } } } # We need to flatten nested arrays, and append the tail. my ($p1, $p2) = @$answer; my @part_1; while (@$p1) { push @part_1, $p1->[0]; $p1 = $p1->[1]; } push @part_1 , map { $in_partition[$_] ? $numbers[$_] : () } $i..$#numbers; my @part_2; while (@$p2) { push @part_2, $p2->[0]; $p2 = $p2->[1]; } push @part_2 , map { $in_partition[$_] ? () : $numbers[$_] } $i..$#numbers; return (\@part_1, \@part_2); }

In reply to Re^2: NP-complete sometimes isn't (A benchmark) by tilly
in thread NP-complete sometimes isn't by tilly

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.