92 lines
1.7 KiB
Plaintext
92 lines
1.7 KiB
Plaintext
class Graph(*args) {
|
|
|
|
struct Node {
|
|
String name,
|
|
Array edges = [],
|
|
Number dist = Inf,
|
|
prev = nil,
|
|
Bool visited = false,
|
|
}
|
|
|
|
struct Edge {
|
|
Number weight,
|
|
Node vertex,
|
|
}
|
|
|
|
has g = Hash()
|
|
|
|
method init {
|
|
args.each { |a|
|
|
self.add_edge(a...)
|
|
}
|
|
}
|
|
|
|
method get(name) {
|
|
g{name}
|
|
}
|
|
|
|
method add_edge(a, b, weight) {
|
|
g{a} ||= Node(name: a)
|
|
g{b} ||= Node(name: b)
|
|
g{a}.edges << Edge(weight, g{b})
|
|
}
|
|
|
|
method push_priority(a, v) {
|
|
var i = 0
|
|
var j = a.end
|
|
while (i <= j) {
|
|
var k = ((i + j) // 2)
|
|
if (a[k].dist >= v.dist) {
|
|
j = k-1
|
|
}
|
|
else {
|
|
i = k+1
|
|
}
|
|
}
|
|
a.insert(i, v)
|
|
}
|
|
|
|
method dijkstra(a, b) {
|
|
g{a}.dist = 0
|
|
var h = []
|
|
self.push_priority(h, g{a})
|
|
while (!h.is_empty) {
|
|
var v = h.shift
|
|
break if (v.name == b)
|
|
v.visited = true
|
|
v.edges.each { |e|
|
|
var u = e.vertex
|
|
if (!u.visited && (v.dist+e.weight <= u.dist)) {
|
|
u.prev = v
|
|
u.dist = (v.dist + e.weight)
|
|
self.push_priority(h, u)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var g = Graph(
|
|
["a", "b", 7],
|
|
["a", "c", 9],
|
|
["a", "f", 14],
|
|
["b", "c", 10],
|
|
["b", "d", 15],
|
|
["c", "d", 11],
|
|
["c", "f", 2],
|
|
["d", "e", 6],
|
|
["e", "f", 9],
|
|
)
|
|
|
|
g.dijkstra('a', 'e')
|
|
|
|
var v = g.get('e')
|
|
var a = []
|
|
while (v != nil) {
|
|
a << v.name
|
|
v = v.prev
|
|
}
|
|
|
|
var path = a.reverse.join
|
|
say "#{g.get('e').dist} #{path}"
|