|
| 1 | +package require Tcl 8.6 |
| 2 | +package require struct |
| 3 | +package require struct::graph |
| 4 | +package require struct::graph::op |
| 5 | + |
| 6 | +proc usage {} { |
| 7 | + puts stderr {Usage: please provide three inputs: a serialized matrix, a source node and a destination node} |
| 8 | + exit 1 |
| 9 | +} |
| 10 | + |
| 11 | +proc isInteger {x} { return [string is integer -strict $x] } |
| 12 | + |
| 13 | +proc parseList {s} { |
| 14 | + set s [string trim $s] |
| 15 | + if {$s eq ""} { usage } |
| 16 | + |
| 17 | + set result {} |
| 18 | + foreach t [split $s ,] { |
| 19 | + set t [string trim $t] |
| 20 | + if {![isInteger $t] || $t < 0} { usage } |
| 21 | + lappend result $t |
| 22 | + } |
| 23 | + return $result |
| 24 | +} |
| 25 | + |
| 26 | +proc createGraph {matrix vertices} { |
| 27 | + set n [llength $vertices] |
| 28 | + if {[llength $matrix] != [expr {$n * $n}]} { usage } |
| 29 | + |
| 30 | + set g [struct::graph] |
| 31 | + $g node insert {*}$vertices |
| 32 | + |
| 33 | + set idx 0 |
| 34 | + foreach i $vertices { |
| 35 | + foreach j $vertices { |
| 36 | + set w [lindex $matrix $idx] |
| 37 | + incr idx |
| 38 | + if {$w > 0} { |
| 39 | + set a [$g arc insert $i $j] |
| 40 | + $g arc setweight $a $w |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + return $g |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +proc main {argv} { |
| 49 | + if {[llength $argv] != 3} { usage } |
| 50 | + lassign $argv matrixStr srcStr destStr |
| 51 | + |
| 52 | + if {![string is integer -strict $srcStr] || ![string is integer -strict $destStr]} { |
| 53 | + usage |
| 54 | + } |
| 55 | + |
| 56 | + set matrix [parseList $matrixStr] |
| 57 | + set n [expr {int(sqrt([llength $matrix]))}] |
| 58 | + if {$n*$n != [llength $matrix]} { usage } |
| 59 | + |
| 60 | + set src [expr {$srcStr + 0}] |
| 61 | + set dest [expr {$destStr + 0}] |
| 62 | + if {$src < 0 || $src >= $n || $dest < 0 || $dest >= $n} { usage } |
| 63 | + |
| 64 | + set vertices [lrange [list {*}[lrepeat $n 0]] 0 end] |
| 65 | + for {set i 0} {$i < $n} {incr i} { lset vertices $i $i } |
| 66 | + |
| 67 | + set g [createGraph $matrix $vertices] |
| 68 | + |
| 69 | + if {[$g node degree $src] == 0 || [$g node degree $dest] == 0} { |
| 70 | + $g destroy |
| 71 | + usage |
| 72 | + } |
| 73 | + |
| 74 | + try { |
| 75 | + set distances [::struct::graph::op::dijkstra $g $src -outputformat distances] |
| 76 | + if {[dict exists $distances $dest]} { |
| 77 | + puts [dict get $distances $dest] |
| 78 | + } else { |
| 79 | + usage |
| 80 | + } |
| 81 | + } on error {err opts} { |
| 82 | + usage |
| 83 | + } finally { |
| 84 | + $g destroy |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | +main $argv |
| 89 | + |
0 commit comments