diff options
| author | James Smith <js5@sanger.ac.uk> | 2022-02-15 14:59:35 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-15 14:59:35 +0000 |
| commit | d6766dc194b9c13a6bdaf34b51dfb29472be9eb7 (patch) | |
| tree | 3409fb74bebfa44eaa890f5b012be991b6f16244 | |
| parent | 1d943d93e690408fa34124bbcecf0f908eff5c1d (diff) | |
| download | perlweeklychallenge-club-d6766dc194b9c13a6bdaf34b51dfb29472be9eb7.tar.gz perlweeklychallenge-club-d6766dc194b9c13a6bdaf34b51dfb29472be9eb7.tar.bz2 perlweeklychallenge-club-d6766dc194b9c13a6bdaf34b51dfb29472be9eb7.zip | |
Update README.md
| -rw-r--r-- | challenge-152/james-smith/README.md | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/challenge-152/james-smith/README.md b/challenge-152/james-smith/README.md index a128b2762a..09f8ad0cb4 100644 --- a/challenge-152/james-smith/README.md +++ b/challenge-152/james-smith/README.md @@ -18,35 +18,68 @@ https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-152/ja ***You are given a triangle array. Write a script to find the minimum sum path from top to bottom.*** +I'm going to outline two different solutions here - the first one is my first approach - which assumed that as +you went down the triangle you could only move to the next line either to the one adjacent to the left or the +right. The second solution removes this constraint and gives the answer in the question... + ## Solution a - can on move down and left or down and right -This doesn't match the output supplied (but feels right) +This doesn't match the output supplied (but feels right). Note we are careful here to make the code "non-destructive" - care has to be taken that we do not shift/modify data from the rows passed in as this will affect the underlying structure. So we note that the `shift` is only done on the `@p` array of totals/paths. + +We start by initalizing a blank row {below the triangle} we than work up the triangle one row at a time, the lowest value for a given cell is the value of the cell plus the lowest value of either the left or right cell below. In the code `$p[0]` is the left hand cell and `$p[1]` is the right hand cell. + +Each time through the loop we generate a new version of `@p` with the best route for each entry. We can (with care) use a `map` to achieve this. We loop through each entry in the incoming data and combine this with the data for the two entries below. If the left hand entry is lower than the right we add the information from the left hand entry to the total, and to the list of numbers chosen to get there. We then need to remove the first entry of `@p` - we can do this with `shift @p` but we don't want that in the resultant array - to "hide" it we multiple the new array `($p[-1])` by `0` which gives us no copies of the array... bang the value we didn't want is gone...! + ```perl sub min_path { my @p = map { [0,[]] } 0,my @t = reverse @{$_[0]}; - for my $r (@t) { - my($l,@q,$z) = shift @p; - ( push @q, $l->[0] < $p[0][0] - ? [ $_+$l->[0], [ $_, @{$l->[1]} ] ] - : [ $_+$p[0][0], [ $_, @{$p[0][1]} ] ] - ), $l = shift @p for @{$r}; - @p = @q; - } + @p = map { $p[0][0] < $p[1][0] + ? [ $_+$p[0][0], [ $_, @{$p[0][1]} ] ] + : [ $_+$p[1][0], [ $_, @{$p[1][1]} ] ] + , (shift @p) x 0 + } @{$_} for @t; + say sprintf 'Minimum value %d: [ %s ]', $p[0][0], join ', ', @{$p[0][1]}; $p[0][0]; } ``` +We can simplify this if we are not worried by the order - by storing a simple value (the minimum total for the path) rather than the pair total/path. + +```perl +sub min_path_total { + my @p = map { 0 } 0, my @t = reverse @{$_[0]}; + @p = map { $_ + $p[ $p[0] < $p[1] ? 0 : 1 ], (shift @p)x 0 } @{$_} for @t; + $p[0]; +} +``` + ## Solution b - can move to any node -This matches the output supplied (but feels wrong) +This matches the output supplied (but feels wrong). In this case we just find the minimum value of each row and sum them together. Again we collect the values used in the path as we work down the triangle and display them at the end. ```perl sub min_path_anydir { + my ($res,@order) = 0; + foreach(@{$_[0]}) { + my $min = $_->[0]; + $_ < $min && ($min = $_) for @{$_}; + $res += $min; + push @order, $min; + } + say sprintf 'Minimum value %d: [ %s ]', $res, join ', ', @order; + $res; +} +``` + +Again we can simplify this function by removing the need to store `@order`. This is simpler as we just need to remove the two lines containing `@order`. Giving us: + +```perl +sub min_path_anydir_total { my $res = 0; foreach(@{$_[0]}) { - my $min = 1e99; - $min = $_ < $min ? $_ : $min for @{$_}; - $res+= $min; + my $min = $_->[0]; + $_ < $min && ($min = $_) for @{$_}; + $res += $min; } $res; } |
