You appear to be making some of the mistakes the author said you needed to avoid - namely, you aren't really cutting down your search space.
You're still performing all these checks on every single number; it would be better to only form the numbers that pass the checks mentioned in comments at the top, rather than to form all numbers and then reject those that fail. Not only that, but you're doing some stuff that doesn't make sense - you could replace your check code with this routine and it would still accept/reject the same numbers but would be tons faster:
sub passes {
my $test_number = shift() || die "no test number";
return 0 if ($test_number =~ /0/); # no zero
return 0 if ($test_number =~ /(.).*\1/); # no dups
for ( split(//,$test_number) ) {
return 0 unless $test_number % $_ == 0 ;
}
return 1;
}
The check about 5 and even numbers is redundant by the point you do it, since if it has 5 and an even number then it either has a 0 or will be rejected by the divisibility test.
So what you need to do is cut down on the number of possibilities to begin with. Say, something like this:
use strict;
sub pass_divcheck { # dups and 0s are assumed already handled
my ($test_number) = @_;
for ( split(//,$test_number) ) {
return 0 unless $test_number % $_ == 0 ;
}
return 1;
}
sub form_number {
my ($num, @remaining_digits) = @_;
print "$num\n" if pass_divcheck($num);
# When dealing with the three low-order digits, we can eliminate som
+e
# possibilities. E.g. Any number divisible by 4 must end in a 2-dig
+it
# number divisible by 4.
my $ndig = length($num);
if ($ndig == 1) {
if ($num % 2 != 0) {
@remaining_digits = grep($_ % 2, @remaining_digits);
}
# After we have one digit, either 5 is already used or we
# can't use 5 later anyway
@remaining_digits = grep($_ % 5, @remaining_digits);
} elsif ($ndig == 2) {
if ($num % 4 != 0) {
@remaining_digits = grep($_ % 4, @remaining_digits);
return if ($num =~ /[48]/);
}
} elsif ($ndig == 3) {
if ($num % 8 != 0) {
@remaining_digits = grep($_ % 8, @remaining_digits);
}
}
my $maxp = $#remaining_digits;
foreach my $p (0..$maxp) {
form_number($remaining_digits[$p] . $num,
@remaining_digits[0..$p-1], @remaining_digits[$p+1..$m
+axp]);
}
}
form_number('', (1..9));
Note that this code won't print the answers out in numerical order. You'll have to sort them with something else.
Update: Got rid of some extraneous code that doesn't add much since the answers don't get generated in numerical order anyway.
--
@/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/;
map{y/X_/\n /;print}map{pop@$_}@/for@/
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.