0: #!/usr/bin/perl
1: # Ed Dijkstra's Shortest-Path, by pope
2: #
3: # Demonstrates practical uses of Infinity
4: # (http://www.perl.com/CPAN-local/doc/FMTEYEWTK/is_numeric.html).
5: # Feed a file consisting neighbourhood matrices like shown below to
6: # this script:
7: #
8: # 0, 50, 10, 40, 45, ~
9: # ~, 0, 15, ~, 10, ~
10: # 20, ~, 0, 15, ~, ~
11: # ~, 20, ~, 0, 35, ~
12: # ~, ~, ~, 30, 0, ~
13: # ~, ~, ~, 3, ~, 0
14: #
15: # Tilde is used to represent unavailable route (infinite distance in
16: # mathematical sense).
17:
18: use strict;
19: use vars qw(@m %state $FINISH $opt_s);
20: use Getopt::Std;
21:
22: BEGIN { $FINISH = 0 }
23:
24: sub sum {
25: my $s;
26: while (@_ > 1) { $s += $m[shift()]->[$_[0]] }
27: $s;
28: }
29:
30: sub output {
31: my %s = @_;
32: print "The shortest route from ", $opt_s, " to: \n";
33: for (keys(%{$s{array}})) {
34: print "$_ is: ", join(", ", @{$state{array}->{$_}->{r}}),
35: " with distance: ", $state{array}->{$_}->{d}, "\n";
36: }
37: }
38:
39: # eat command line argument
40:
41: getopts('s:');
42: defined(my $start = $opt_s) or die "Usage: $0 -s start_node matrices_file";
43:
44: while (<>) { next if /^\s*$/;s/\s//g;s/~/Infinity/g;push @m, [split(/,\s*/, $_)] }
45:
46: {
47: my ($cnt, $cnt1);
48: %state = ( node => undef,
49: track => undef,
50: array => {map {$cnt++ => $_ }
51: map { {s => 0, d => $_, r => [$start, $cnt1++]} }
52: @{$m[$start]}}
53: );
54: }
55:
56: my $loop = 0;
57:
58: while (not $FINISH) {
59: my ($cnt, $cnt1);
60:
61: # select the unselected
62: my @min = grep {/\d/}
63: map {!$state{array}->{$_}->{s} ? $_ : undef}
64: sort {
65: my $aa = $state{array}->{$a}->{d};
66: my $bb = $state{array}->{$b}->{d};
67: $aa <=> $bb;
68: }
69: keys(%{$state{array}});
70:
71: # set node, track and s
72: @state{'node','track'} = ($min[0], $state{array}->{$min[0]}->{r});
73: $state{array}->{$min[0]}->{s} = 1;
74:
75: # prepare the state for the next loop
76: for (@min) {
77: if ( (my $nd = sum(@{$state{track}}, $_)) <
78: $state{array}->{$_}->{d}) {
79: $state{array}->{$_}->{d} = $nd;
80: $state{array}->{$_}->{r} = [@{$state{track}}, $_];
81: }
82: }
83: $FINISH = 1 if (++$loop >= @{$m[0]} );
84: }
85: output(%state);
In reply to Shortest Path by pope
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |