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