Yitzchak Scott-Thoennes wrote: > > On Thu, Aug 14, 2003 at 11:02:19AM +0100, Jonathan E. Paton wrote: > > Easy, the fastest method is to use stack based notation (RPN). This > > completely avoids the need for those pesky brackets. The stack is > > arranged into each of the permutations, and then the operators applied > > in each permutation. There is only 24 permutations of the numbers, and > > 64 permutations of the operators, combined there is 1536 different > > expressions. We need to select only those evaluating to 21. > > Each of those 1536 expressions has 5 variants corresponding to > the five different ways of parenthesizing the non-RPN version. > You only seem to check 1 of the 5. > > Where n is one of the numbers and op is one of the ops, you > need to try: > > RPN non-RPN > n n n n op op op n op (n op (n op n)) > n n n op n op op n op ((n op n) op n) > n n n op op n op (n op (n op n)) op n > n n op n n op op (n op n) op (n op n) > n n op n op n op ((n op n) op n) op n > > Here's my try. Note that special handling may be needed to avoid an > answer for which the computer gets 20.9999999999999 or similar, when > the true answer would be 21. This could involve using something like > Math::BigRat instead of floating point math, or checking for an answer > within some small margin of 21 (which can be done somewhat > automatically by setting the deprecated $# var to the appropriate > precision and stringifying the number). On my system, fudging this > way isn't needed for this problem, but not all the world is 64-bit > IEEE. > > #!perl -l > use strict; > # $# = "%.6g"; # uncomment this if needed for your system's floating point math > use warnings; > > # build series of ops to use (4*4*4) > my @ops = []; > @ops = map {["+",@$_],["-",@$_],["/",@$_],["*",@$_]} @ops for 1..3; > > # apply each possible precedence (4*4*4*5) > my @templates = map { > sprintf("%%d %s (%%d %s (%%d %s %%d)) eq 21", @$_), > sprintf("%%d %s ((%%d %s %%d) %s %%d) eq 21", @$_), > sprintf("(%%d %s (%%d %s %%d)) %s %%d eq 21", @$_), > sprintf("(%%d %s %%d) %s (%%d %s %%d) eq 21", @$_), > sprintf("((%%d %s %%d) %s %%d) %s %%d eq 21", @$_)} @ops; > > # and try each permutation of numbers (4*4*4*5*24) > for my $nums (permute(1,5,6,7)) { > eval(sprintf $_, @$nums) and printf("$_\n", @$nums) for @templates; > } > > sub permute { > @_ <= 1 ? (wantarray ? [EMAIL PROTECTED] : 1) : do { > my @ret; > for my $i (0..$#_) { > push @ret, grep push(@$_, $_[$i]), permute(@_[0..$i-1,$i+1..$#_]) > } > @ret; > } > }
or, using a golf glob trick (with a fix for *): #!/usr/bin/perl -l use strict; my $n = '{1,5,6,7}'; my $op = '{+,-,%,/}'; tr/%/*/, /1/ && /5/ && /6/ && /7/ && eval == 21 && print for <($n$op$n)$op($n$op$n)>, <(($n$op$n)$op$n)$op$n>, <($n$op($n$op$n))$op$n>, <$n$op(($n$op$n)$op$n)>, <$n$op($n$op($n$op$n))>, -- Rick Klement