in reply to Divide array of integers into most similar value halves

Yay for fancy comp sci terms. It is NP-complete! (or is it "NP hard"?)

Given 100 numbers, this code finds a likely-optimal solution in about 1 second. If you are unlucky, it can spend a very long time after that not finding any better solutions. :)

#!/usr/bin/perl -w use strict; sub halfWeights { my @weights= sort { $b <=> $a } @_; my $dist= 0; $dist += $_ for @weights; $dist /= 2; my $best= $dist; my @sol; my @idx= ( 0 ); while( 1 ) { $dist -= $weights[$idx[-1]]; for( abs($dist) ) { if( $_ < $best ) { $best= $_; @sol= @idx; printf STDERR "%+g: %s\n", $_, join( ", ", @weights[@i +dx] ); return @weights[ @sol ] if( 0 == $_ ); } } if( 0 < $dist ) { push @idx, 1 + $idx[-1] } else { $dist += $weights[ $idx[-1]++ ]; } while( @weights <= $idx[-1] ) { pop @idx; return @weights[ @sol ] if( 1 == @idx ); $dist += $weights[ $idx[-1]++ ]; } } } @ARGV= ( 100 ) if( ! @ARGV ); push @ARGV, $ARGV[0]*$ARGV[0] if( 1 == @ARGV ); if( 2 == @ARGV ) { my $cnt= shift @ARGV; my $max= shift @ARGV; push @ARGV, 1 + int rand($max) while( @ARGV < $cnt ); } elsif( 3 == @ARGV ) { my $cnt= shift @ARGV; while( @ARGV < $cnt ) { push @ARGV, $ARGV[-2] + $ARGV[-1]; } } halfWeights( @ARGV );

Note that if you have fractional weights, then the way that things are computed will likely cause a growing accumulation of errors that won't impact the likely-optimal solution much but could cause serious misrepresentation of how close other solutions really are if you wait the hundreds of years and more that it could spend contemplating them.

- tye        

  • Comment on Re: Divide array of integers into most similar value halves (good enough)
  • Download Code