matrix_path_4-ways_best_2.pl 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 13 August 2016
  5. # Website: https://github.com/trizen
  6. # In the 5 by 5 matrix below, the minimal path sum from the top left
  7. # to the bottom right, by moving left, right, up, and down, is equal to 2297.
  8. # Problem from: https://projecteuler.net/problem=83
  9. # (this algorithm is scalable only up to 7x7 matrices)
  10. use 5.010;
  11. use strict;
  12. use warnings;
  13. use Memoize qw(memoize);
  14. my @matrix = (
  15. [131, 673, 234, 103, 18],
  16. [201, 96, 342, 965, 150],
  17. [630, 803, 746, 422, 111],
  18. [537, 699, 497, 121, 956],
  19. [805, 732, 524, 37, 331],
  20. );
  21. memoize('path');
  22. my $end = $#matrix;
  23. sub path {
  24. my ($i, $j, $seen) = @_;
  25. my @seen = split(' ', $seen);
  26. my $valid = sub {
  27. my %seen;
  28. @seen{@seen} = ();
  29. not exists $seen{"$_[0]:$_[1]"};
  30. };
  31. if ($i >= $end and $j >= $end) {
  32. return $matrix[$i][$j];
  33. }
  34. my @points;
  35. if ($j < $end and $valid->($i, $j + 1)) {
  36. push @points, [$i, $j + 1];
  37. }
  38. if ($i > 0 and $valid->($i - 1, $j)) {
  39. push @points, [$i - 1, $j];
  40. }
  41. if ($j > 0 and $valid->($i, $j - 1)) {
  42. push @points, [$i, $j - 1];
  43. }
  44. if ($i < $end and $valid->($i + 1, $j)) {
  45. push @points, [$i + 1, $j];
  46. }
  47. my $min = 'inf';
  48. my $snn = join(' ', sort (@seen, map { join(':', @$_) } @points));
  49. foreach my $point (@points) {
  50. my $sum = path(@$point, $snn);
  51. $min = $sum if $sum < $min;
  52. }
  53. $min + $matrix[$i][$j];
  54. }
  55. say path(0, 0, '');