kappa has asked for the wisdom of the Perl Monks concerning the following question:
Update down there
Good day, fellow monks.
My question is more of academic interest than practical. Here's a simple task from an old CS collegiate contest: Sums in a Triangle.
It's definitely NOT of the type Perl excels at but still I decided to give it a try. (Actually, my main motivation is that a working Python solution exists!)
My C solution works fast and passed the online judge, it's O(n^2) and very efficient. But the best Perl code I came up with requires at least 6 seconds in the worst case on my fairly powerful Core 2 Duo 2.66Ghz box. It uses the same algorithm I used in C.
If anyone feels like playing with it, I'd be very interested in results.
My C code (before compressing into 256 chars which is not interesting):
My best Perl code (strict was removed):#include <stdio.h> int data[100][100]; int sumintr(int nr) { int r, col; for(r = nr - 1 - 1; r >= 0; --r) { for(col = 0; col <= r; ++col) { data[r][col] += data[r + 1][ data[r + 1][col] > data[r + 1][col + 1] ? col : col + 1 ]; } } return data[0][0]; } int main() { int ns, nr, s, r, col; scanf("%d\n", &ns); for(s = 0; s < ns; ++s) { scanf("%d\n", &nr); for(r = 0; r < nr; ++r) { for(col = 0; col <= r; ++col) scanf("%d", &data[r][col]); } printf("%d\n", sumintr(nr)); } }
#!/usr/bin/perl for (1..<>) { @tr = map { [split ' ', <>] } 1 .. <>; $prev = pop @tr; for $cur (reverse @tr) { $g = $prev->[0]; for (0 .. $#$cur) { $cur->[$_] += ($f = $g) > ($g = $prev->[$_ + 1]) ? $f : $g; } $prev = $cur; } print "$prev->[0]\n"; }
The worst test case I'm banging my head against: http://dl.dropbox.com/u/360558/input_big.txt.gz (will decompress to 14Mb)
(Probably, my first reaction to such a question would be something like: "Wow, compiled C code is faster than Perl! Thank you, Captain Obvious!" I would definitely not spend several hours examining NYTProf beautiful reports unless I knew that some guy solved it in Python (albeit using a lot of memory, which is, by the way, a good indicator of a different algorithm)).
Update. Big thanks to ikegami and zwon for their suggestions in comments! I just decreased my runtime by almost 30% implementing them! The last version looks like this:
#!/usr/bin/perl undef $/; @file = split ' ', scalar <>; for (1 .. shift(@file)) { $rows = $file[$cur++]; @s = (0) x ($rows + 1); for (1 .. $rows) { ($i, $y) = (0, 0); $cur += $_ - 1; for ($cur .. $cur + $_ - 1) { $x = $y; $y = $s[$i]; $s[$i++] = $file[$_] + ($x > $y ? $x : $y); } } $m = 0; $m = $m > $_ ? $m : $_ for @s; print "$m\n"; $cur += $rows; }
It does not pass the SPOJ judge yet, although. But the box which will run it in 2 sec should be only twice as fast as my desktop :)
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Adding a lot of small integers
by ikegami (Patriarch) on Jan 09, 2010 at 18:17 UTC | |
by kappa (Chaplain) on Jan 09, 2010 at 23:28 UTC | |
by ikegami (Patriarch) on Jan 10, 2010 at 08:17 UTC | |
by kappa (Chaplain) on Jan 10, 2010 at 00:11 UTC | |
by JavaFan (Canon) on Jan 09, 2010 at 23:07 UTC | |
by ikegami (Patriarch) on Jan 10, 2010 at 08:16 UTC | |
by JavaFan (Canon) on Jan 10, 2010 at 11:05 UTC | |
|
Re: Adding a lot of small integers
by zwon (Abbot) on Jan 09, 2010 at 20:25 UTC | |
by kappa (Chaplain) on Jan 10, 2010 at 01:07 UTC | |
|
Re: Adding a lot of small integers
by spx2 (Deacon) on Jan 09, 2010 at 18:00 UTC |