Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
3
Task/Dijkstras-algorithm/00-META.yaml
Normal file
3
Task/Dijkstras-algorithm/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Dijkstra's_algorithm
|
||||
note: Classic CS problems
|
||||
140
Task/Dijkstras-algorithm/00-TASK.txt
Normal file
140
Task/Dijkstras-algorithm/00-TASK.txt
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
'''Dijkstra's algorithm''', conceived by Dutch computer scientist [[wp:Edsger Dijkstra|Edsger Dijkstra]] in 1956 and published in 1959, is a [[wp:graph search algorithm|graph search algorithm]] that solves the single-source [[wp:shortest path problem|shortest path problem]] for a [[wp:graph (mathematics)|graph]] with non-negative [[wp:edge (graph theory)|edge]] path costs, producing a [[wp:shortest path tree|shortest path tree]].
|
||||
|
||||
This algorithm is often used in [[wp:routing|routing]] and as a subroutine in other graph algorithms.
|
||||
|
||||
|
||||
For a given source [[wp:vertex (graph theory)|vertex]] (node) in the graph, the algorithm finds the path with lowest cost (i.e. the shortest path) between that vertex and every other vertex.
|
||||
|
||||
|
||||
;For instance:
|
||||
If the vertices of the graph represent cities and edge path costs represent driving distances between pairs of cities connected by a direct road, Dijkstra's algorithm can be used to find the shortest route between one city and all other cities.
|
||||
|
||||
As a result, the shortest path first is widely used in network [[wp:routing protocol|routing protocol]]s, most notably:
|
||||
::* [[wp:IS-IS|IS-IS]] (Intermediate System to Intermediate System) and
|
||||
::* [[wp:OSPF|OSPF]] (Open Shortest Path First).
|
||||
|
||||
|
||||
;Important note:
|
||||
The inputs to Dijkstra's algorithm are a directed and weighted graph consisting of '''2''' or more nodes, generally represented by:
|
||||
::* an adjacency matrix or list, and
|
||||
::* a start node.
|
||||
|
||||
|
||||
A destination node is not specified.
|
||||
|
||||
The output is a set of edges depicting the shortest path to each destination node.
|
||||
|
||||
<!-- this is the original example: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
For the example we start:
|
||||
<pre>
|
||||
a->b,cost=7,lastNode=a; a->c,cost=9,lastNode=a; a->d,cost=NA,lastNode=a; a->e,cost=NA,lastNode=a; a->f,cost=14,lastNode=a
|
||||
The lowest cost is a->b so we add a->b to the output. There is a connection from b->d so we update our input to
|
||||
a->c,cost=9,lastNode=a; a->d,cost=22,lastNode=b; a->e,cost=NA,lastNode=a; a->f,cost=14,lastNode=a
|
||||
The lowest cost is a->c so we add a->c to the output. Paths to d and f are cheaper via c so we update our input to
|
||||
a->d,cost=20,lastNode=c; a->e,cost=NA,lastNode=a; a->f,cost=11,lastNode=c
|
||||
The lowest cost is a->f so we add c->f to the output. We update our input to
|
||||
a->d,cost=20,lastNode=c; a->e,cost=NA,lastNode=a
|
||||
The lowest cost is a->d so we add c->d to the output. There is a connection from d->e so we update our input to
|
||||
a->e,cost=26,lastNode=d
|
||||
Which just leaves adding d->e to the output.
|
||||
The output should now be [d->e;c->d;c->f;a->c;a->b]
|
||||
</pre>
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ !-->
|
||||
|
||||
;An example, starting with:
|
||||
<syntaxhighlight lang="text"> a──►b, cost=7, lastNode=a
|
||||
a──►c, cost=9, lastNode=a
|
||||
a──►d, cost=NA, lastNode=a
|
||||
a──►e, cost=NA, lastNode=a
|
||||
a──►f, cost=14, lastNode=a
|
||||
|
||||
The lowest cost is a──►b so a──►b is added to the output.
|
||||
|
||||
There is a connection from b──►d so the input is updated to:
|
||||
a──►c, cost=9, lastNode=a
|
||||
a──►d, cost=22, lastNode=b
|
||||
a──►e, cost=NA, lastNode=a
|
||||
a──►f, cost=14, lastNode=a
|
||||
|
||||
The lowest cost is a──►c so a──►c is added to the output.
|
||||
|
||||
Paths to d and f are cheaper via c so the input is updated to:
|
||||
a──►d, cost=20, lastNode=c
|
||||
a──►e, cost=NA, lastNode=a
|
||||
a──►f, cost=11, lastNode=c
|
||||
|
||||
The lowest cost is a──►f so c──►f is added to the output.
|
||||
|
||||
The input is updated to:
|
||||
a──►d, cost=20, lastNode=c
|
||||
a──►e, cost=NA, lastNode=a
|
||||
|
||||
The lowest cost is a──►d so c──►d is added to the output.
|
||||
|
||||
There is a connection from d──►e so the input is updated to:
|
||||
a──►e, cost=26, lastNode=d
|
||||
|
||||
Which just leaves adding d──►e to the output.
|
||||
|
||||
The output should now be:
|
||||
[ d──►e
|
||||
c──►d
|
||||
c──►f
|
||||
a──►c
|
||||
a──►b ] </syntaxhighlight>
|
||||
|
||||
|
||||
;Task:
|
||||
# Implement a version of Dijkstra's algorithm that outputs a set of edges depicting the shortest path to each reachable node from an origin.
|
||||
# Run your program with the following directed graph starting at node <big> '''a'''.</big>
|
||||
# Write a program which interprets the output from the above and use it to output the shortest path from node <big> '''a''' </big> to nodes <big> '''e''' </big> and <big> '''f'''. </big>
|
||||
|
||||
::::::::: {| class="wikitable" style="text-align: center; float: left"
|
||||
|+ Vertices
|
||||
|-
|
||||
! Number !! Name
|
||||
|-
|
||||
| 1 || a
|
||||
|-
|
||||
| 2 || b
|
||||
|-
|
||||
| 3 || c
|
||||
|-
|
||||
| 4 || d
|
||||
|-
|
||||
| 5 || e
|
||||
|-
|
||||
| 6 || f
|
||||
|}
|
||||
{| class="wikitable" style="text-align: center"
|
||||
|+ Edges
|
||||
|-
|
||||
! Start !! End !! Cost
|
||||
|-
|
||||
| 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
|
||||
|}
|
||||
|
||||
|
||||
You can use numbers or names to identify vertices in your program.
|
||||
|
||||
|
||||
;See also
|
||||
* [https://www.youtube.com/watch?v=cSxnOm5aceA Dijkstra's Algorithm vs. A* Search vs. Concurrent Dijkstra's Algorithm (youtube)]
|
||||
<br><br>
|
||||
|
||||
51
Task/Dijkstras-algorithm/11l/dijkstras-algorithm.11l
Normal file
51
Task/Dijkstras-algorithm/11l/dijkstras-algorithm.11l
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
T Edge
|
||||
String start
|
||||
String end
|
||||
Int cost
|
||||
|
||||
F (start, end, cost)
|
||||
.start = start
|
||||
.end = end
|
||||
.cost = cost
|
||||
|
||||
T Graph
|
||||
[Edge] edges
|
||||
Set[String] vertices
|
||||
|
||||
F (edges)
|
||||
.edges = edges.map((s, e, c) -> Edge(s, e, c))
|
||||
.vertices = Set(.edges.map(e -> e.start)).union(Set(.edges.map(e -> e.end)))
|
||||
|
||||
F dijkstra(source, dest)
|
||||
assert(source C .vertices)
|
||||
V dist = Dict(.vertices, vertex -> (vertex, Float.infinity))
|
||||
V previous = Dict(.vertices, vertex -> (vertex, ‘’))
|
||||
dist[source] = 0
|
||||
V q = copy(.vertices)
|
||||
V neighbours = Dict(.vertices, vertex -> (vertex, [(String, Int)]()))
|
||||
L(start, end, cost) .edges
|
||||
neighbours[start].append((end, cost))
|
||||
|
||||
L !q.empty
|
||||
V u = min(q, key' vertex -> @dist[vertex])
|
||||
q.remove(u)
|
||||
I dist[u] == Float.infinity | u == dest
|
||||
L.break
|
||||
L(v, cost) neighbours[u]
|
||||
V alt = dist[u] + cost
|
||||
I alt < dist[v]
|
||||
dist[v] = alt
|
||||
previous[v] = u
|
||||
|
||||
Deque[String] s
|
||||
V u = dest
|
||||
L previous[u] != ‘’
|
||||
s.append_left(u)
|
||||
u = previous[u]
|
||||
s.append_left(u)
|
||||
R s
|
||||
|
||||
V graph = 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)])
|
||||
print(graph.dijkstra(‘a’, ‘e’))
|
||||
141
Task/Dijkstras-algorithm/ALGOL-68/dijkstras-algorithm-1.alg
Normal file
141
Task/Dijkstras-algorithm/ALGOL-68/dijkstras-algorithm-1.alg
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
# -*- coding: utf-8 -*- #
|
||||
|
||||
COMMENT REQUIRED BY "prelude_dijkstras_algorithm.a68" CO
|
||||
MODE ROUTELEN = ~;
|
||||
ROUTELEN route len infinity = max ~;
|
||||
PROC route len add = (VERTEX v, ROUTE r)ROUTELEN:
|
||||
route len OF v + route len OF r; # or MAX(v,r) #
|
||||
MODE VERTEXPAYLOAD = ~;
|
||||
PROC dijkstra fix value error = (STRING msg)BOOL:
|
||||
(put(stand error, (msg, new line)); FALSE);
|
||||
#PROVIDES:#
|
||||
# VERTEX*=~* #
|
||||
# ROUTE*=~* #
|
||||
# vertex route*=~* #
|
||||
END COMMENT
|
||||
|
||||
MODE VALVERTEX = STRUCT(
|
||||
ROUTELEN route len,
|
||||
FLEX[0]ROUTE route,
|
||||
ROUTE shortest route,
|
||||
VERTEXPAYLOAD vertex data
|
||||
);
|
||||
|
||||
MODE VERTEX = REF VALVERTEX;
|
||||
MODE VERTEXYIELD = PROC(VERTEX)VOID; # used to "generate" VERTEX path #
|
||||
PRIO INIT = 1; # The same PRIOrity as +:= etc #
|
||||
OP INIT = (VERTEX self, VERTEXPAYLOAD vertex data)VERTEX:
|
||||
self := (route len infinity, (), NIL, vertex data);
|
||||
|
||||
# It may be faster to preallocate "queue", rather then grow a FLEX #
|
||||
OP +:= = (REF FLEX[]VERTEX in list, VERTEX rhs)REF FLEX[]VERTEX: (
|
||||
[UPB in list+1]VERTEX out list;
|
||||
out list[:UPB in list] := in list;
|
||||
out list[UPB out list] := rhs;
|
||||
in list := out list # EXIT #
|
||||
);
|
||||
|
||||
MODE VALROUTE = STRUCT(VERTEX from, to, ROUTELEN route len#, ROUTEPAYLOAD#);
|
||||
MODE ROUTE = REF VALROUTE;
|
||||
|
||||
OP +:= = (REF FLEX[]ROUTE in list, ROUTE rhs)REF FLEX[]ROUTE: (
|
||||
[UPB in list+1]ROUTE out list;
|
||||
out list[:UPB in list] := in list;
|
||||
out list[UPB out list] := rhs;
|
||||
in list := out list # EXIT #
|
||||
);
|
||||
|
||||
MODE VERTEXROUTE = UNION(VERTEX, ROUTE);
|
||||
MODE VERTEXROUTEYIELD = PROC(VERTEXROUTE)VOID;
|
||||
|
||||
################################################################
|
||||
# Finally: now the strong typing is in place, the task code... #
|
||||
################################################################
|
||||
PROC vertex route gen dijkstra = (
|
||||
VERTEX source, target,
|
||||
REF[]VALROUTE route list,
|
||||
VERTEXROUTEYIELD yield
|
||||
)VOID:(
|
||||
|
||||
# initialise the route len for BOTH directions on each route #
|
||||
FOR this TO UPB route list DO
|
||||
ROUTE route = route list[this];
|
||||
route OF from OF route +:= route;
|
||||
# assume route lens is the same in both directions, this i.e. NO A-B gradient NOR 1-way streets #
|
||||
route OF to OF route +:= (HEAP VALROUTE := (to OF route, from OF route, route len OF route))
|
||||
OD;
|
||||
|
||||
COMMENT
|
||||
Algorithium Performance "about" O(n**2)...
|
||||
Optimisations:
|
||||
a) bound index in [lwb queue:UPB queue] for search
|
||||
b) delay adding vertices until they are actually encountered
|
||||
It may be faster to preallocate "queue" vertex list, rather then grow a FLEX
|
||||
END COMMENT
|
||||
|
||||
PROC vertex gen nearest = (REF FLEX[]VERTEX queue, VERTEXYIELD yield)VOID: (
|
||||
INT vertices done := 0, lwb queue := 1;
|
||||
ROUTELEN shortest route len done := -route len infinity;
|
||||
WHILE vertices done <= UPB queue ANDF shortest route len done NE route len infinity DO
|
||||
ROUTELEN shortest route len := route len infinity;
|
||||
# skip done elements: #
|
||||
FOR this FROM lwb queue TO UPB queue DO
|
||||
VERTEX this vertex := queue[this];
|
||||
IF NOT(shortest route len done < route len OF this vertex) THEN
|
||||
lwb queue := this; # remember for next time #
|
||||
break
|
||||
FI
|
||||
OD;
|
||||
break:
|
||||
# find vertex with shortest path attached #
|
||||
FOR this FROM lwb queue TO UPB queue DO VERTEX this vertex := queue[this];
|
||||
IF shortest route len done < route len OF this vertex ANDF
|
||||
route len OF this vertex < shortest route len THEN
|
||||
shortest route len := route len OF this vertex FI
|
||||
OD;
|
||||
# update the other vertices with shortest path found #
|
||||
FOR this FROM lwb queue TO UPB queue DO VERTEX this vertex := queue[this];
|
||||
IF route len OF this vertex = shortest route len THEN
|
||||
vertices done +:= 1; yield(this vertex) FI
|
||||
OD;
|
||||
shortest route len done := shortest route len
|
||||
OD
|
||||
);
|
||||
|
||||
route len OF target := 0;
|
||||
FLEX[0]VERTEX queue := target;
|
||||
|
||||
# FOR VERTEX this vertex IN # vertex gen nearest(queue#) DO (#,
|
||||
## (VERTEX this vertex)VOID: (
|
||||
FOR this TO UPB route OF this vertex DO ROUTE this route = (route OF this vertex)[this];
|
||||
|
||||
# If this vertex has not been encountered before, then add to queue #
|
||||
IF route len OF to OF this route = route len infinity THEN queue +:= to OF this route FI;
|
||||
|
||||
ROUTELEN route len = route len add(this vertex, this route);
|
||||
IF route len < route len OF to OF this route THEN
|
||||
route len OF to OF this route := route len;
|
||||
shortest route OF to OF this route := this route
|
||||
FI
|
||||
OD;
|
||||
|
||||
IF this vertex IS source THEN done FI
|
||||
# OD#));
|
||||
IF NOT dijkstra fix value error("no path found") THEN stop FI;
|
||||
|
||||
############################
|
||||
# Now: generate the result #
|
||||
############################
|
||||
done: (
|
||||
VERTEX this vertex := source;
|
||||
WHILE
|
||||
yield(this vertex);
|
||||
ROUTE this route = shortest route OF this vertex;
|
||||
# WHILE # this route ISNT ROUTE(NIL) DO
|
||||
yield(this route);
|
||||
this vertex := from OF this route
|
||||
OD
|
||||
)
|
||||
);
|
||||
|
||||
SKIP
|
||||
52
Task/Dijkstras-algorithm/ALGOL-68/dijkstras-algorithm-2.alg
Normal file
52
Task/Dijkstras-algorithm/ALGOL-68/dijkstras-algorithm-2.alg
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/a68g --script #
|
||||
# -*- coding: utf-8 -*- #
|
||||
|
||||
CO REQUIRED BY "prelude_dijkstras_algorithm.a68" CO
|
||||
MODE ROUTELEN = INT,
|
||||
ROUTELEN route len infinity = max int,
|
||||
PROC route len add = (VERTEX v, ROUTE r)ROUTELEN:
|
||||
route len OF v + route len OF r; # or MAX(v,r) #
|
||||
MODE VERTEXPAYLOAD = STRING,
|
||||
PROC dijkstra fix value error = (STRING msg)BOOL:
|
||||
(put(stand error, (msg, new line)); FALSE);
|
||||
#PROVIDES:#
|
||||
# VERTEX*=~* #
|
||||
# ROUTE*=~* #
|
||||
# vertex route*=~* #
|
||||
PR READ "prelude_dijkstras_algorithm.a68" PR;
|
||||
|
||||
FORMAT vertex data fmt = $g$;
|
||||
|
||||
main:(
|
||||
INT upb graph = 6, upb route list = 9;
|
||||
|
||||
HEAP[upb graph]VALVERTEX graph;
|
||||
|
||||
# name the key vertices #
|
||||
FOR this TO UPB graph DO graph[this] INIT STRING("abcdef"[this]) OD;
|
||||
|
||||
# declare some variables of the same name #
|
||||
VERTEX a := graph[1], b := graph[2], c := graph[3],
|
||||
d := graph[4], e := graph[5], f := graph[6];
|
||||
|
||||
# define the graph #
|
||||
HEAP FLEX[upb route list]VALROUTE route list := (
|
||||
(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)
|
||||
);
|
||||
|
||||
# FOR VERTEXROUTE vertex route IN # vertex route gen dijkstra(a, e, route list#) DO #,
|
||||
## (VERTEXROUTE vertex route)VOID: (
|
||||
CASE vertex route IN
|
||||
(VERTEX vertex): printf((vertex data fmt, vertex data OF vertex)),
|
||||
(ROUTE route): printf(($" --"g(0)"-> "$, route len OF route))
|
||||
ESAC
|
||||
# OD #));
|
||||
print(new line)
|
||||
|
||||
# TODO: generate random 100000 VERTEX graph test case and test performance - important #
|
||||
|
||||
)
|
||||
781
Task/Dijkstras-algorithm/ATS/dijkstras-algorithm.ats
Normal file
781
Task/Dijkstras-algorithm/ATS/dijkstras-algorithm.ats
Normal file
|
|
@ -0,0 +1,781 @@
|
|||
(*------------------------------------------------------------------*)
|
||||
|
||||
(* Dijkstra's algorithm. *)
|
||||
|
||||
(* I demonstrate Dijkstra's algorithm using a rudimentary priority
|
||||
queue. For a practical implementation, you would use a fast
|
||||
implementation of priority queue. *)
|
||||
|
||||
%{^
|
||||
#include <math.h>
|
||||
%}
|
||||
|
||||
#include "share/atspre_staload.hats"
|
||||
staload UN = "prelude/SATS/unsafe.sats"
|
||||
|
||||
#define NIL list_nil ()
|
||||
#define :: list_cons
|
||||
|
||||
typedef flt = double
|
||||
macdef zero = 0.0
|
||||
macdef infinity = $extval (flt, "INFINITY")
|
||||
|
||||
prfn
|
||||
mul_compare_lte
|
||||
{i, j, n : nat | i <= j}
|
||||
()
|
||||
:<prf> [i * n <= j * n] void =
|
||||
mul_gte_gte_gte {j - i, n} ()
|
||||
|
||||
prfn
|
||||
mul_compare_lt
|
||||
{i, j, n : int | 0 <= i; i < j; 1 <= n}
|
||||
()
|
||||
:<prf> [i * n < j * n] void =
|
||||
mul_compare_lte {i + 1, j, n} ()
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
(* Constructing a graph. *)
|
||||
|
||||
fn
|
||||
extract_vertices
|
||||
(edges : List @(string, string, double))
|
||||
:<!wrt> [n : nat]
|
||||
@(arrayref (string, n),
|
||||
size_t n) =
|
||||
let
|
||||
fun
|
||||
list_the_vertices
|
||||
{m : nat}
|
||||
{n0 : nat}
|
||||
.<m>.
|
||||
(edges : list (@(string, string, double), m),
|
||||
accum : list (string, n0),
|
||||
n0 : size_t n0)
|
||||
:<!wrt> [n1 : nat]
|
||||
@(list (string, n1), size_t n1) =
|
||||
case+ edges of
|
||||
| NIL => @(accum, n0)
|
||||
| @(v1, v2, _) :: tail =>
|
||||
let
|
||||
implement list_find$pred<string> x = (x = v1)
|
||||
in
|
||||
case+ list_find_opt accum of
|
||||
| ~ None_vt () =>
|
||||
let
|
||||
implement list_find$pred<string> x = (x = v2)
|
||||
in
|
||||
case+ list_find_opt accum of
|
||||
| ~ None_vt () =>
|
||||
list_the_vertices (tail, v2 :: v1 :: accum,
|
||||
succ (succ n0))
|
||||
| ~ Some_vt _ =>
|
||||
list_the_vertices (tail, v1 :: accum, succ n0)
|
||||
end
|
||||
| ~ Some_vt _ =>
|
||||
let
|
||||
implement list_find$pred<string> x = (x = v2)
|
||||
in
|
||||
case+ list_find_opt accum of
|
||||
| ~ None_vt () =>
|
||||
list_the_vertices (tail, v2 :: accum, succ n0)
|
||||
| ~ Some_vt _ => list_the_vertices (tail, accum, n0)
|
||||
end
|
||||
end
|
||||
|
||||
prval () = lemma_list_param edges
|
||||
val @(vertex_lst, n) = list_the_vertices (edges, NIL, i2sz 0)
|
||||
val vertex_arr = arrayref_make_list<string> (sz2i n, vertex_lst)
|
||||
in
|
||||
@(vertex_arr, n)
|
||||
end
|
||||
|
||||
fn
|
||||
vertex_name_to_index
|
||||
{n : int}
|
||||
(vertex_arr : arrayref (string, n),
|
||||
n : size_t n,
|
||||
name : string)
|
||||
:<!ref> Option ([i : nat | i < n] size_t i) =
|
||||
let
|
||||
fun
|
||||
loop {i : nat | i <= n}
|
||||
.<n - i>.
|
||||
(i : size_t i)
|
||||
:<!ref> Option ([i : nat | i < n] size_t i) =
|
||||
if i = n then
|
||||
None ()
|
||||
else if name = vertex_arr[i] then
|
||||
Some i
|
||||
else
|
||||
loop (succ i)
|
||||
|
||||
prval () = lemma_arrayref_param vertex_arr
|
||||
in
|
||||
loop (i2sz 0)
|
||||
end
|
||||
|
||||
fn
|
||||
make_adjacency_matrix
|
||||
(edges : List @(string, string, double))
|
||||
:<!refwrt> [n : nat]
|
||||
@(matrixref (flt, n, n),
|
||||
arrayref (string, n),
|
||||
size_t n) =
|
||||
let
|
||||
val @(vertex_arr, n) = extract_vertices edges
|
||||
val adj_matrix = matrixref_make_elt<flt> (n, n, infinity)
|
||||
|
||||
fun
|
||||
loop {m : nat}
|
||||
.<m>.
|
||||
(edges : list (@(string, string, double), m))
|
||||
:<!refwrt> void =
|
||||
case+ edges of
|
||||
| NIL => ()
|
||||
| @(v1, v2, cost) :: tail =>
|
||||
let
|
||||
val- Some i = vertex_name_to_index (vertex_arr, n, v1)
|
||||
and Some j = vertex_name_to_index (vertex_arr, n, v2)
|
||||
in
|
||||
adj_matrix[i, n, j] := cost;
|
||||
loop tail
|
||||
end
|
||||
|
||||
prval () = lemma_list_param edges
|
||||
in
|
||||
loop edges;
|
||||
@(adj_matrix, vertex_arr, n)
|
||||
end
|
||||
|
||||
fn
|
||||
fprint_vertex_path
|
||||
{n : int}
|
||||
(outf : FILEref,
|
||||
vertex_arr : arrayref (string, n),
|
||||
path : List ([i : nat | i < n] size_t i),
|
||||
cost_opt : Option flt,
|
||||
cost_column_no : size_t)
|
||||
: void =
|
||||
let
|
||||
fun
|
||||
loop {m : nat}
|
||||
.<m>.
|
||||
(path : list ([i : nat | i < n] size_t i, m),
|
||||
column_no : size_t)
|
||||
: size_t =
|
||||
case+ path of
|
||||
| NIL => column_no
|
||||
| i :: NIL =>
|
||||
begin
|
||||
fprint! (outf, vertex_arr[i]);
|
||||
column_no + strlen vertex_arr[i]
|
||||
end
|
||||
| i :: tail =>
|
||||
begin
|
||||
fprint! (outf, vertex_arr[i], " -> ");
|
||||
loop (tail, column_no + strlen vertex_arr[i] + i2sz 4)
|
||||
end
|
||||
|
||||
prval () = lemma_list_param path
|
||||
val column_no = loop (path, i2sz 1)
|
||||
in
|
||||
case+ cost_opt of
|
||||
| None () => ()
|
||||
| Some cost =>
|
||||
let
|
||||
var i : size_t = column_no
|
||||
in
|
||||
while (i < cost_column_no)
|
||||
begin
|
||||
fprint! (outf, " ");
|
||||
i := succ i
|
||||
end;
|
||||
fprint! (outf, "(cost = ", cost, ")")
|
||||
end
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
(* A binary-heap priority queue, similar to the Pascal in Robert
|
||||
Sedgewick, "Algorithms", 2nd ed. (reprinted with corrections),
|
||||
1989. Note that Sedgewick does an extract-max, whereas we do an
|
||||
extract-min.
|
||||
|
||||
Niklaus Wirth, within the heapsort implementation of "Algorithms +
|
||||
Data Structures = Programs", has, I will note, some Pascal code
|
||||
that is practically the same as Sedgewick's. Can we trace that code
|
||||
back farther to Algol?
|
||||
|
||||
We do not have "goto" for Sedgewick's "downheap" (or Wirth's
|
||||
"sift"), but do have mutual tail call as an obvious alternative to
|
||||
the "goto". Nevertheless, because the code "jumped to" is small, I
|
||||
simply use a macro to duplicate it. *)
|
||||
|
||||
dataprop PQUEUE_N_MAX (n_max : int) =
|
||||
| {0 <= n_max}
|
||||
PQUEUE_N_MAX (n_max)
|
||||
|
||||
typedef pqueue (priority_t : t@ype+,
|
||||
value_t : t@ype+,
|
||||
n : int,
|
||||
n_max : int) =
|
||||
[n <= n_max]
|
||||
@{
|
||||
(* An earlier version of this structure stored a copy of n_max,
|
||||
but the following use of the PQUEUE_N_MAX prop eliminates the
|
||||
need for that. Instead the information is kept only at
|
||||
typechecking time. *)
|
||||
pf = PQUEUE_N_MAX (n_max) |
|
||||
arr = arrayref (@(priority_t, value_t), n_max + 1),
|
||||
n = size_t n
|
||||
}
|
||||
|
||||
prfn
|
||||
lemma_pqueue_param
|
||||
{n_max : int}
|
||||
{n : int}
|
||||
{priority_t, value_t : t@ype}
|
||||
(pq : pqueue (priority_t, value_t, n, n_max))
|
||||
:<prf> [0 <= n; n <= n_max] void =
|
||||
lemma_g1uint_param (pq.n)
|
||||
|
||||
extern praxi
|
||||
lemma_pqueue_size
|
||||
{n_max : int}
|
||||
{n : int}
|
||||
{priority_t, value_t : t@ype}
|
||||
(pq : pqueue (priority_t, value_t, n, n_max))
|
||||
:<prf> [n1 : int | n1 == n] void
|
||||
|
||||
extern fn {priority_t : t@ype}
|
||||
pqueue$cmp :
|
||||
(priority_t, priority_t) -<> int
|
||||
|
||||
extern fn {priority_t : t@ype}
|
||||
pqueue$priority_min :
|
||||
() -<> priority_t
|
||||
|
||||
implement pqueue$cmp<double> (x, y) = compare (x, y)
|
||||
implement pqueue$priority_min<double> () = neg infinity
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
pqueue_make_empty
|
||||
{n_max : int}
|
||||
(n_max : size_t n_max,
|
||||
arbitrary_entry : @(priority_t, value_t))
|
||||
:<!wrt> pqueue (priority_t, value_t, 0, n_max) =
|
||||
let
|
||||
(* Currently an array is allocated whose size is the proven
|
||||
bound. It might be better to use a smaller array and allow
|
||||
reallocation up to this maximum size, or to break the array
|
||||
into pieces. *)
|
||||
|
||||
prval () = lemma_g1uint_param n_max
|
||||
val arr =
|
||||
arrayref_make_elt<@(priority_t, value_t)>
|
||||
(succ n_max, arbitrary_entry)
|
||||
in
|
||||
@{pf = PQUEUE_N_MAX {n_max} () |
|
||||
arr = arr,
|
||||
n = i2sz 0}
|
||||
end
|
||||
|
||||
fn {}
|
||||
pqueue_clear
|
||||
{n_max : int}
|
||||
{n : int}
|
||||
{priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
(pq : &pqueue (priority_t, value_t, n, n_max)
|
||||
>> pqueue (priority_t, value_t, 0, n_max))
|
||||
:<!wrt> void =
|
||||
let
|
||||
prval PQUEUE_N_MAX () = pq.pf (* Proves 0 <= n_max. *)
|
||||
in
|
||||
pq := @{pf = pq.pf |
|
||||
arr = pq.arr,
|
||||
n = i2sz 0}
|
||||
end
|
||||
|
||||
fn {}
|
||||
pqueue_is_empty
|
||||
{n_max : int}
|
||||
{n : int}
|
||||
{priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
(pq : pqueue (priority_t, value_t, n, n_max))
|
||||
:<> bool (n == 0) =
|
||||
(pq.n) = i2sz 0
|
||||
|
||||
fn {}
|
||||
pqueue_size
|
||||
{n_max : int}
|
||||
{n : int}
|
||||
{priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
(pq : pqueue (priority_t, value_t, n, n_max))
|
||||
:<> size_t n =
|
||||
pq.n
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
_upheap {n_max : pos}
|
||||
{n : int | n <= n_max}
|
||||
{k0 : nat | k0 <= n}
|
||||
(arr : arrayref (@(priority_t, value_t), n_max + 1),
|
||||
k0 : size_t k0)
|
||||
:<!refwrt> void =
|
||||
let
|
||||
macdef lt (x, y) = (pqueue$cmp<priority_t> (,(x), ,(y)) < 0)
|
||||
macdef prio x = ,(x).0
|
||||
|
||||
val entry = arr[k0]
|
||||
|
||||
fun
|
||||
loop {k : nat | k <= n}
|
||||
.<k>.
|
||||
(k : size_t k)
|
||||
:<!refwrt> void =
|
||||
if k = i2sz 0 then
|
||||
arr[k] := entry
|
||||
else
|
||||
let
|
||||
val kh = half k
|
||||
in
|
||||
if (prio entry) \lt (prio arr[kh]) then
|
||||
begin
|
||||
arr[k] := arr[kh];
|
||||
loop kh
|
||||
end
|
||||
else
|
||||
arr[k] := entry
|
||||
end
|
||||
in
|
||||
arr[0] := @(pqueue$priority_min<priority_t> (), arr[0].1);
|
||||
loop k0
|
||||
end
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
pqueue_insert
|
||||
{n_max : int}
|
||||
{n : int | n < n_max}
|
||||
(pq : &pqueue (priority_t, value_t, n, n_max)
|
||||
>> pqueue (priority_t, value_t, n + 1, n_max),
|
||||
entry : @(priority_t, value_t))
|
||||
:<!refwrt> void =
|
||||
let
|
||||
prval () = lemma_g1uint_param (pq.n)
|
||||
val arr = pq.arr
|
||||
and n1 = succ (pq.n)
|
||||
in
|
||||
arr[n1] := entry;
|
||||
_upheap {n_max} {n + 1} (arr, n1);
|
||||
pq := @{pf = pq.pf |
|
||||
arr = arr,
|
||||
n = n1}
|
||||
end
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
_downheap {n_max : pos}
|
||||
{n : pos | n <= n_max}
|
||||
(arr : arrayref (@(priority_t, value_t), n_max + 1),
|
||||
n : size_t n)
|
||||
:<!refwrt> void =
|
||||
let
|
||||
macdef lt (x, y) = (pqueue$cmp<priority_t> (,(x), ,(y)) < 0)
|
||||
macdef prio x = ,(x).0
|
||||
|
||||
val entry = arr[1]
|
||||
and nh = half n
|
||||
|
||||
fun
|
||||
loop {k : pos | k <= n}
|
||||
.<n - k>.
|
||||
(k : size_t k)
|
||||
:<!refwrt> void =
|
||||
let
|
||||
macdef move_data i =
|
||||
if (prio entry) \lt (prio arr[,(i)]) then
|
||||
arr[k] := entry
|
||||
else
|
||||
begin
|
||||
arr[k] := arr[,(i)];
|
||||
loop ,(i)
|
||||
end
|
||||
in
|
||||
if nh < k then
|
||||
arr[k] := entry
|
||||
else
|
||||
let
|
||||
stadef j = 2 * k
|
||||
prval () = prop_verify {j <= n} ()
|
||||
val j : size_t j = k + k
|
||||
in
|
||||
if j < n then
|
||||
let
|
||||
stadef j1 = j + 1
|
||||
prval () = prop_verify {j1 <= n} ()
|
||||
val j1 : size_t j1 = succ j
|
||||
in
|
||||
if ~((prio arr[j]) \lt (prio arr[j1])) then
|
||||
move_data j1
|
||||
else
|
||||
move_data j
|
||||
end
|
||||
else
|
||||
move_data j
|
||||
end
|
||||
end
|
||||
in
|
||||
loop (i2sz 1)
|
||||
end
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
pqueue_peek
|
||||
{n_max : int}
|
||||
{n : pos | n <= n_max}
|
||||
(pq : pqueue (priority_t, value_t, n, n_max))
|
||||
:<!ref> @(priority_t, value_t) =
|
||||
let
|
||||
val arr = pq.arr
|
||||
in
|
||||
arr[1]
|
||||
end
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
pqueue_delete
|
||||
{n_max : int}
|
||||
{n : pos | n <= n_max}
|
||||
(pq : &pqueue (priority_t, value_t, n, n_max)
|
||||
>> pqueue (priority_t, value_t, n - 1, n_max))
|
||||
:<!refwrt> void =
|
||||
let
|
||||
val @{pf = pf |
|
||||
arr = arr,
|
||||
n = n} = pq
|
||||
in
|
||||
if i2sz 0 < pred n then
|
||||
begin
|
||||
arr[1] := arr[n];
|
||||
_downheap {n_max} {n - 1} (arr, pred n)
|
||||
end;
|
||||
pq := @{pf = pf |
|
||||
arr = arr,
|
||||
n = pred n}
|
||||
end
|
||||
|
||||
fn {priority_t : t@ype}
|
||||
{value_t : t@ype}
|
||||
pqueue_extract
|
||||
{n_max : int}
|
||||
{n : pos | n <= n_max}
|
||||
(pq : &pqueue (priority_t, value_t, n, n_max)
|
||||
>> pqueue (priority_t, value_t, n - 1, n_max))
|
||||
:<!refwrt> @(priority_t, value_t) =
|
||||
let
|
||||
val retval = pqueue_peek<priority_t><value_t> {n_max} {n} pq
|
||||
in
|
||||
pqueue_delete<priority_t><value_t> {n_max} {n} pq;
|
||||
retval
|
||||
end
|
||||
|
||||
local (* A little unit testing of the priority queue
|
||||
implementation. *)
|
||||
#define NMAX 10
|
||||
in
|
||||
var pq = pqueue_make_empty<double><int> (i2sz NMAX, @(0.0, 0))
|
||||
val- true = pqueue_is_empty pq
|
||||
val- true = (pqueue_size pq = i2sz 0)
|
||||
val () = pqueue_insert (pq, @(3.0, 3))
|
||||
val () = pqueue_insert (pq, @(5.0, 5))
|
||||
val () = pqueue_insert (pq, @(1.0, 1))
|
||||
val () = pqueue_insert (pq, @(2.0, 2))
|
||||
val () = pqueue_insert (pq, @(4.0, 4))
|
||||
val- false = pqueue_is_empty pq
|
||||
val- true = (pqueue_size pq = i2sz 5)
|
||||
val- @(1.0, 1) = pqueue_extract<double> pq
|
||||
val- @(2.0, 2) = pqueue_extract<double> pq
|
||||
val- @(3.0, 3) = pqueue_extract<double> pq
|
||||
val- @(4.0, 4) = pqueue_extract<double> pq
|
||||
val- @(5.0, 5) = pqueue_extract<double> pq
|
||||
val- true = pqueue_is_empty pq
|
||||
val- true = (pqueue_size pq = i2sz 0)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
(* Dijkstra's algorithm. *)
|
||||
|
||||
fn
|
||||
dijkstra_algorithm
|
||||
{n : int}
|
||||
{source : nat | source < n}
|
||||
(adj_matrix : matrixref (flt, n, n),
|
||||
n : size_t n,
|
||||
source : size_t source)
|
||||
(* Returns total-costs and previous-hops arrays. *)
|
||||
:<!refwrt> @(arrayref (flt, n),
|
||||
arrayref ([i : nat | i <= n] size_t i, n)) =
|
||||
let
|
||||
prval () = lemma_matrixref_param adj_matrix
|
||||
|
||||
typedef index_t = [i : nat | i <= n] size_t i
|
||||
typedef defined_index_t = [i : nat | i < n] size_t i
|
||||
val index_t_undefined : size_t n = n
|
||||
|
||||
val arbitrary_pq_entry : @(flt, defined_index_t) =
|
||||
@(0.0, i2sz 0)
|
||||
|
||||
val prev = arrayref_make_elt<index_t> (n, index_t_undefined)
|
||||
and cost = arrayref_make_elt<flt> (n, infinity)
|
||||
val () = cost[source] := zero
|
||||
|
||||
(* The priority queue never gets larger than m_max. There is code
|
||||
below that proves this; thus there is no risk of overrunning
|
||||
the queue's storage (unless the queue implementation itself is
|
||||
made unsafe). FIXME: Is it possible to prove a tighter bound on
|
||||
the size of the priority queue? *)
|
||||
stadef m_max = (n * n) + n + n
|
||||
prval () = mul_pos_pos_pos (mul_make {n, n} ())
|
||||
prval () = prop_verify {n + n < m_max} ()
|
||||
val m_max : size_t m_max = (n * n) + n + n
|
||||
|
||||
typedef pqueue_t (m : int) =
|
||||
[0 <= m; m <= m_max]
|
||||
pqueue (flt, defined_index_t, m, m_max)
|
||||
typedef pqueue_t =
|
||||
[m : int] pqueue_t m
|
||||
|
||||
fn
|
||||
pq_make_empty ()
|
||||
:<!wrt> pqueue_t 0 =
|
||||
(* Create a priority queue, whose maximum size is our proven
|
||||
upper bound on the queue size. *)
|
||||
pqueue_make_empty<flt><defined_index_t>
|
||||
(m_max, arbitrary_pq_entry)
|
||||
|
||||
var pq = pq_make_empty ()
|
||||
val active = arrayref_make_elt<bool> (n, true)
|
||||
var num_active : [i : nat | i <= n] size_t i = n
|
||||
|
||||
fun
|
||||
fill_pq {i : nat | i <= n}
|
||||
.<n - i>.
|
||||
(pq : &pqueue_t i >> pqueue_t n,
|
||||
i : size_t i)
|
||||
:<!refwrt> void =
|
||||
if i <> n then
|
||||
begin
|
||||
pqueue_insert {m_max} {i} (pq, @(cost[i], i));
|
||||
fill_pq {i + 1} (pq, succ i)
|
||||
end
|
||||
|
||||
fun
|
||||
extract_min
|
||||
{m0 : pos | m0 + n <= m_max}
|
||||
.<m0>.
|
||||
(pq : &pqueue_t m0 >> pqueue_t m1)
|
||||
:<!refwrt> #[m1 : nat | m1 < m0]
|
||||
@(flt, defined_index_t) =
|
||||
let
|
||||
val @(priority, vertex) =
|
||||
pqueue_extract<flt><defined_index_t> {m_max} {m0} pq
|
||||
in
|
||||
if active[vertex] then
|
||||
@(priority, vertex)
|
||||
else if pqueue_is_empty {m_max} pq then
|
||||
arbitrary_pq_entry
|
||||
else
|
||||
extract_min pq
|
||||
end
|
||||
|
||||
fun
|
||||
main_loop {num_active0 : nat | num_active0 <= n}
|
||||
{qsize0 : nat}
|
||||
{qlimit0 : int | 0 <= qlimit0;
|
||||
qsize0 <= qlimit0 + n}
|
||||
.<num_active0>.
|
||||
(* The pf_qlimit0 prop helps us prove a bound on the
|
||||
size of the priority queue. We need it because the
|
||||
proof capabilities built into ATS have very limited
|
||||
ability to handle multiplication. *)
|
||||
(pf_qlimit0 : MUL (n - num_active0, n, qlimit0) |
|
||||
pq : &pqueue_t qsize0 >> pqueue_t 0,
|
||||
num_active : &size_t num_active0 >> size_t num_active1)
|
||||
:<!refwrt> #[num_active1 : nat | num_active1 <= num_active0]
|
||||
void =
|
||||
if num_active = i2sz 0 then
|
||||
pqueue_clear pq
|
||||
else if pqueue_is_empty {m_max} {qsize0} pq then
|
||||
let (* This should not happen. *)
|
||||
val- false = true
|
||||
in
|
||||
end
|
||||
else
|
||||
let
|
||||
prval () = mul_elim pf_qlimit0
|
||||
prval () =
|
||||
prop_verify {qsize0 <= ((n - num_active0) * n) + n} ()
|
||||
prval () = mul_compare_lt {n - num_active0, n, n} ()
|
||||
prval () = prop_verify {qsize0 < m_max} ()
|
||||
|
||||
val @(priority, u) = extract_min pq
|
||||
prval [qsize : int] () = lemma_pqueue_size {m_max} pq
|
||||
prval () = lemma_pqueue_param {m_max} {qsize} pq
|
||||
prval () = prop_verify {qsize < qsize0} ()
|
||||
prval () = prop_verify {qsize < m_max} ()
|
||||
|
||||
val () = active[u] := false
|
||||
and () = num_active := pred num_active
|
||||
|
||||
fun
|
||||
loop_over_vertices
|
||||
{v : nat | v <= n}
|
||||
{m0 : nat | qsize <= m0; m0 <= qsize + v}
|
||||
.<n - v>.
|
||||
(pq : &pqueue_t m0 >> pqueue_t m1,
|
||||
v : size_t v)
|
||||
:<!refwrt> #[m1 : int | qsize <= m1; m1 <= qsize + n]
|
||||
void =
|
||||
if v = n then
|
||||
()
|
||||
else if ~active[v] then
|
||||
loop_over_vertices {v + 1} {m0} (pq, succ v)
|
||||
else
|
||||
let
|
||||
val alternative = cost[u] + adj_matrix[u, n, v]
|
||||
in
|
||||
if alternative < cost[v] then
|
||||
let
|
||||
prval () = prop_verify {m0 < m_max} ()
|
||||
in
|
||||
cost[v] := alternative;
|
||||
prev[v] := u;
|
||||
|
||||
(* Rather than lower the priority of v, this
|
||||
implementation inserts a new entry for v and
|
||||
ignores obsolete queue entries. Queue entries
|
||||
are obsolete if the vertex's entry in the
|
||||
"active" array is false. *)
|
||||
|
||||
pqueue_insert<flt><defined_index_t>
|
||||
{m_max} {m0}
|
||||
(pq, @(alternative, v));
|
||||
|
||||
loop_over_vertices {v + 1} {m0 + 1}
|
||||
(pq, succ v)
|
||||
end
|
||||
else
|
||||
loop_over_vertices {v + 1} {m0} (pq, succ v)
|
||||
end
|
||||
|
||||
val () = loop_over_vertices {0} {qsize} (pq, i2sz 0)
|
||||
in
|
||||
main_loop {num_active0 - 1}
|
||||
(MULind pf_qlimit0 | pq, num_active)
|
||||
end
|
||||
in
|
||||
fill_pq {0} (pq, i2sz 0);
|
||||
main_loop {n} {n} (MULbas () | pq, num_active);
|
||||
@(cost, prev)
|
||||
end
|
||||
|
||||
fn
|
||||
least_cost_path
|
||||
{n : int}
|
||||
(source : [i : nat | i < n] size_t i,
|
||||
prev : arrayref ([i : nat | i <= n] size_t i, n),
|
||||
n : size_t n,
|
||||
destination : [i : nat | i < n] size_t i)
|
||||
:<!refwrt> Option (List1 ([i : nat | i < n] size_t i)) =
|
||||
let
|
||||
prval () = lemma_arrayref_param prev
|
||||
|
||||
typedef index_t = [i : nat | i <= n] size_t i
|
||||
typedef defined_index_t = [i : nat | i < n] size_t i
|
||||
val index_t_undefined : size_t n = n
|
||||
|
||||
fun
|
||||
loop {i : nat | i <= n}
|
||||
.<n - i>.
|
||||
(u : defined_index_t,
|
||||
accum : List1 defined_index_t,
|
||||
loop_counter : size_t i)
|
||||
:<!refwrt> Option (List1 defined_index_t) =
|
||||
if loop_counter = n then
|
||||
None ()
|
||||
else if u = source then
|
||||
Some accum
|
||||
else
|
||||
let
|
||||
val previous = prev[u]
|
||||
in
|
||||
if previous = index_t_undefined then
|
||||
None ()
|
||||
else
|
||||
loop (previous, previous :: accum, succ loop_counter)
|
||||
end
|
||||
in
|
||||
loop (destination, destination :: NIL, i2sz 0)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
val example_edges =
|
||||
$list (@("a", "b", 7.0),
|
||||
@("a", "c", 9.0),
|
||||
@("a", "f", 14.0),
|
||||
@("b", "c", 10.0),
|
||||
@("b", "d", 15.0),
|
||||
@("c", "d", 11.0),
|
||||
@("c", "f", 2.0),
|
||||
@("d", "e", 6.0),
|
||||
@("e", "f", 9.0))
|
||||
|
||||
implement
|
||||
main0 () =
|
||||
let
|
||||
val @(adj_matrix, vertex_arr, n) =
|
||||
make_adjacency_matrix example_edges
|
||||
|
||||
prval [n : int] EQINT () = eqint_make_guint n
|
||||
|
||||
val- Some a = vertex_name_to_index (vertex_arr, n, "a")
|
||||
val- Some e = vertex_name_to_index (vertex_arr, n, "e")
|
||||
val- Some f = vertex_name_to_index (vertex_arr, n, "f")
|
||||
|
||||
val @(cost, prev) = dijkstra_algorithm (adj_matrix, n, a)
|
||||
|
||||
val- Some path_a_to_e = least_cost_path {n} (a, prev, n, e)
|
||||
val- Some path_a_to_f = least_cost_path {n} (a, prev, n, f)
|
||||
|
||||
var u : [i : nat | i <= n] size_t i
|
||||
val cost_column_no = i2sz 20
|
||||
in
|
||||
println! ("The requested paths:");
|
||||
fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_e,
|
||||
Some cost[e], cost_column_no);
|
||||
println! ();
|
||||
fprint_vertex_path (stdout_ref, vertex_arr, path_a_to_f,
|
||||
Some cost[f], cost_column_no);
|
||||
println! ();
|
||||
println! ();
|
||||
println! ("All paths (in no particular order):");
|
||||
for (u := i2sz 0; u <> n; u := succ u)
|
||||
case+ least_cost_path {n} (a, prev, n, u) of
|
||||
| None () =>
|
||||
println! ("There is no path from ", vertex_arr[a], " to ",
|
||||
vertex_arr[u], ".")
|
||||
| Some path =>
|
||||
begin
|
||||
fprint_vertex_path (stdout_ref, vertex_arr, path,
|
||||
Some cost[u], cost_column_no);
|
||||
println! ()
|
||||
end
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
50
Task/Dijkstras-algorithm/AWK/dijkstras-algorithm-1.awk
Normal file
50
Task/Dijkstras-algorithm/AWK/dijkstras-algorithm-1.awk
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
NF == 3 { graph[$1,$2] = $3 }
|
||||
NF == 2 {
|
||||
weight = shortest($1, $2)
|
||||
n = length(path)
|
||||
p = $1
|
||||
for (i = 2; i < n; i++)
|
||||
p = p "-" path[i]
|
||||
print p "-" $2 " (" weight ")"
|
||||
}
|
||||
|
||||
# Edge weights are in graph[node1,node2]
|
||||
# Returns the weight of the shortest path
|
||||
# Shortest path is in path[1] ... path[n]
|
||||
function shortest(from, to, queue, q, dist, v, i, min, edge, e, prev, n) {
|
||||
delete path
|
||||
dist[from] = 0
|
||||
queue[q=1] = from
|
||||
|
||||
while (q > 0) {
|
||||
min = 1
|
||||
for (i = 2; i <= q; i++)
|
||||
if (dist[queue[i]] < dist[queue[min]])
|
||||
min = i
|
||||
v = queue[min]
|
||||
queue[min] = queue[q--]
|
||||
|
||||
if (v == to)
|
||||
break
|
||||
for (edge in graph) {
|
||||
split(edge, e, SUBSEP)
|
||||
if (e[1] != v)
|
||||
continue
|
||||
if (!(e[2] in dist) || dist[e[1]] + graph[edge] < dist[e[2]]) {
|
||||
dist[e[2]] = dist[e[1]] + graph[edge]
|
||||
prev[e[2]] = e[1]
|
||||
queue[++q] = e[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v != to)
|
||||
return "n/a"
|
||||
|
||||
# Build the path
|
||||
n = 1
|
||||
for (v = to; v != from; v = prev[v])
|
||||
n++
|
||||
for (v = to; n > 0; v = prev[v])
|
||||
path[n--] = v
|
||||
return dist[to]
|
||||
}
|
||||
18
Task/Dijkstras-algorithm/AWK/dijkstras-algorithm-2.awk
Normal file
18
Task/Dijkstras-algorithm/AWK/dijkstras-algorithm-2.awk
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
$ cat dijkstra.txt
|
||||
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
|
||||
a e
|
||||
a f
|
||||
f a
|
||||
|
||||
$ awk -f dijkstra.awk dijkstra.txt
|
||||
a-c-d-e (26)
|
||||
a-c-f (11)
|
||||
f-a (n/a)
|
||||
32
Task/Dijkstras-algorithm/Ada/dijkstras-algorithm-1.ada
Normal file
32
Task/Dijkstras-algorithm/Ada/dijkstras-algorithm-1.ada
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
private with Ada.Containers.Ordered_Maps;
|
||||
generic
|
||||
type t_Vertex is (<>);
|
||||
package Dijkstra is
|
||||
|
||||
type t_Graph is limited private;
|
||||
|
||||
-- Defining a graph (since limited private, only way to do this is to use the Build function)
|
||||
type t_Edge is record
|
||||
From, To : t_Vertex;
|
||||
Weight : Positive;
|
||||
end record;
|
||||
type t_Edges is array (Integer range <>) of t_Edge;
|
||||
function Build (Edges : in t_Edges; Oriented : in Boolean := True) return t_Graph;
|
||||
|
||||
-- Computing path and distance
|
||||
type t_Path is array (Integer range <>) of t_Vertex;
|
||||
function Shortest_Path (Graph : in out t_Graph;
|
||||
From, To : in t_Vertex) return t_Path;
|
||||
function Distance (Graph : in out t_Graph;
|
||||
From, To : in t_Vertex) return Natural;
|
||||
|
||||
private
|
||||
package Neighbor_Lists is new Ada.Containers.Ordered_Maps (Key_Type => t_Vertex, Element_Type => Positive);
|
||||
type t_Vertex_Data is record
|
||||
Neighbors : Neighbor_Lists.Map; -- won't be affected after build
|
||||
-- Updated each time a function is called with a new source
|
||||
Previous : t_Vertex;
|
||||
Distance : Natural;
|
||||
end record;
|
||||
type t_Graph is array (t_Vertex) of t_Vertex_Data;
|
||||
end Dijkstra;
|
||||
91
Task/Dijkstras-algorithm/Ada/dijkstras-algorithm-2.ada
Normal file
91
Task/Dijkstras-algorithm/Ada/dijkstras-algorithm-2.ada
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
with Ada.Containers.Ordered_Sets;
|
||||
package body Dijkstra is
|
||||
|
||||
Infinite : constant Natural := Natural'Last;
|
||||
|
||||
-- ----- Graph constructor
|
||||
function Build (Edges : in t_Edges; Oriented : in Boolean := True) return t_Graph is
|
||||
begin
|
||||
return Answer : t_Graph := (others => (Neighbors => Neighbor_Lists.Empty_Map,
|
||||
Previous => t_Vertex'First,
|
||||
Distance => Natural'Last)) do
|
||||
for Edge of Edges loop
|
||||
Answer(Edge.From).Neighbors.Insert (Key => Edge.To, New_Item => Edge.Weight);
|
||||
if not Oriented then
|
||||
Answer(Edge.To).Neighbors.Insert (Key => Edge.From, New_Item => Edge.Weight);
|
||||
end if;
|
||||
end loop;
|
||||
end return;
|
||||
end Build;
|
||||
|
||||
-- ----- Paths / distances data updating in case of computation request for a new source
|
||||
procedure Update_For_Source (Graph : in out t_Graph;
|
||||
From : in t_Vertex) is
|
||||
function Nearer (Left, Right : in t_Vertex) return Boolean is
|
||||
(Graph(Left).Distance < Graph(Right).Distance or else
|
||||
(Graph(Left).Distance = Graph(Right).Distance and then Left < Right));
|
||||
package Ordered is new Ada.Containers.Ordered_Sets (Element_Type => t_Vertex, "<" => Nearer);
|
||||
use Ordered;
|
||||
Remaining : Set := Empty_Set;
|
||||
begin
|
||||
-- First, let's check if vertices data are already computed for this source
|
||||
if Graph(From).Distance /= 0 then
|
||||
-- Reset distances and remaining vertices for a new source
|
||||
for Vertex in Graph'range loop
|
||||
Graph(Vertex).Distance := (if Vertex = From then 0 else Infinite);
|
||||
Remaining.Insert (Vertex);
|
||||
end loop;
|
||||
-- ----- The Dijkstra algorithm itself
|
||||
while not Remaining.Is_Empty
|
||||
-- If some targets are not connected to source, at one point, the remaining
|
||||
-- distances will all be infinite, hence the folllowing stop condition
|
||||
and then Graph(Remaining.First_Element).Distance /= Infinite loop
|
||||
declare
|
||||
Nearest : constant t_Vertex := Remaining.First_Element;
|
||||
procedure Update_Neighbor (Position : in Neighbor_Lists.Cursor) is
|
||||
use Neighbor_Lists;
|
||||
Neighbor : constant t_Vertex := Key (Position);
|
||||
In_Remaining : Ordered.Cursor := Remaining.Find (Neighbor);
|
||||
Try_Distance : constant Natural :=
|
||||
(if In_Remaining = Ordered.No_Element
|
||||
then Infinite -- vertex already reached, this distance will fail the update test below
|
||||
else Graph(Nearest).Distance + Element (Position));
|
||||
begin
|
||||
if Try_Distance < Graph(Neighbor).Distance then
|
||||
-- Update distance/path data and reorder the remaining set
|
||||
Remaining.Delete (In_Remaining);
|
||||
Graph(Neighbor).Distance := Try_Distance;
|
||||
Graph(Neighbor).Previous := Nearest;
|
||||
Remaining.Insert (Neighbor);
|
||||
end if;
|
||||
end Update_Neighbor;
|
||||
begin
|
||||
Remaining.Delete_First;
|
||||
Graph(Nearest).Neighbors.Iterate (Update_Neighbor'Access);
|
||||
end;
|
||||
end loop;
|
||||
end if;
|
||||
end Update_For_Source;
|
||||
|
||||
-- ----- Bodies for the interfaced functions
|
||||
function Shortest_Path (Graph : in out t_Graph;
|
||||
From, To : in t_Vertex) return t_Path is
|
||||
function Recursive_Build (From, To : in t_Vertex) return t_Path is
|
||||
(if From = To then (1 => From)
|
||||
else Recursive_Build(From, Graph(To).Previous) & (1 => To));
|
||||
begin
|
||||
Update_For_Source (Graph, From);
|
||||
if Graph(To).Distance = Infinite then
|
||||
raise Constraint_Error with "No path from " & From'Img & " to " & To'Img;
|
||||
end if;
|
||||
return Recursive_Build (From, To);
|
||||
end Shortest_Path;
|
||||
|
||||
function Distance (Graph : in out t_Graph;
|
||||
From, To : in t_Vertex) return Natural is
|
||||
begin
|
||||
Update_For_Source (Graph, From);
|
||||
return Graph(To).Distance;
|
||||
end Distance;
|
||||
|
||||
end Dijkstra;
|
||||
39
Task/Dijkstras-algorithm/Ada/dijkstras-algorithm-3.ada
Normal file
39
Task/Dijkstras-algorithm/Ada/dijkstras-algorithm-3.ada
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
with Dijkstra;
|
||||
procedure Test_Dijkstra is
|
||||
subtype t_Tested_Vertices is Character range 'a'..'f';
|
||||
package Tested is new Dijkstra (t_Vertex => t_Tested_Vertices);
|
||||
use Tested;
|
||||
Graph : t_Graph := Build (Edges => (('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)));
|
||||
procedure Display_Path (From, To : in t_Tested_Vertices) is
|
||||
function Path_Image (Path : in t_Path; Start : Boolean := True) return String is
|
||||
((if Start then "["
|
||||
elsif Path'Length /= 0 then ","
|
||||
else "") &
|
||||
(if Path'Length = 0 then "]"
|
||||
else Path(Path'First) & Path_Image(Path(Path'First+1..Path'Last), Start => False)));
|
||||
begin
|
||||
Put ("Path from '" & From & "' to '" & To & "' = ");
|
||||
Put_Line (Path_Image (Shortest_Path (Graph, From, To))
|
||||
& " distance =" & Distance (Graph, From, To)'Img);
|
||||
exception
|
||||
when others => Put_Line("no path");
|
||||
end Display_Path;
|
||||
begin
|
||||
Display_Path ('a', 'e');
|
||||
Display_Path ('a', 'f');
|
||||
New_Line;
|
||||
for From in t_Tested_Vertices loop
|
||||
for To in t_Tested_Vertices loop
|
||||
Display_Path (From, To);
|
||||
end loop;
|
||||
end loop;
|
||||
end Test_Dijkstra;
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
100 O$ = "A" : T$ = "EF"
|
||||
110 DEF FN N(P) = ASC(MID$(N$,P+(P=0),1))-64
|
||||
120 DIM D(26),UNVISITED(26)
|
||||
130 DIM PREVIOUS(26) : TRUE = 1
|
||||
140 LET M = -1 : INFINITY = M
|
||||
150 FOR I = 0 TO 26
|
||||
160 LET D(I) = INFINITY : NEXT
|
||||
170 FOR NE = M TO 1E38 STEP .5
|
||||
180 READ C$
|
||||
190 IF LEN(C$) THEN NEXT
|
||||
200 DIM C(NE),FROM(NE),T(NE)
|
||||
210 DIM PC(NE) : RESTORE
|
||||
220 FOR I = 0 TO NE
|
||||
230 READ C(I), N$
|
||||
240 LET FROM(I) = FN N(1)
|
||||
250 LET UNVISITED(FR(I)) = TRUE
|
||||
260 LET T(I) = FN N(3)
|
||||
270 LET UNVISITED(T(I)) = TRUE
|
||||
290 NEXT
|
||||
300 N$ = O$ : O = FN N(0)
|
||||
310 D(O) = 0
|
||||
320 FOR CV = O TO EMPTY STEP 0
|
||||
330 FOR I = 0 TO NE
|
||||
340 IF FROM(I) = CV THEN N = T(I) : D = D(CV) + C(I) : IF (D(N) = INFINITY) OR (D < D(N)) THEN D(N) = D : PREVIOUS(N) = CV : PC(N) = C(I)
|
||||
350 NEXT I
|
||||
360 LET UNVISITED(CV) = FALSE
|
||||
370 LET MV = EMPTY
|
||||
380 FOR I = 1 TO 26
|
||||
390 IF UNVISITED(I) THEN MD = D(MV) * (MV <> INFINITY) + INFINITY * (MV = INFINITY) : IF (D(I) <> INFINITY) AND ((MD = INFINITY) OR (D(I) < MD)) THEN MV = I
|
||||
400 NEXT I
|
||||
410 LET CV = MV * (MD <> INF)
|
||||
420 NEXT CV : M$ = CHR$(13)
|
||||
430 PRINT "SHORTEST PATH";
|
||||
440 FOR I = 1 TO LEN(T$)
|
||||
450 LET N$ = MID$(T$, I, 1)
|
||||
460 PRINT M$ " FROM " O$;
|
||||
470 PRINT " TO "; : N = FN N(0)
|
||||
480 IF D(N) = INFINITY THEN PRINT N$" DOES NOT EXIST.";
|
||||
490 IF D(N) <> INFINITY THEN FOR N = N TO FALSE STEP 0 : PRINT CHR$(N + 64); : IF N < > O THEN PRINT " <- "; : N = PREVIOUS(N): NEXT N
|
||||
500 IF D(N) <> INFINITY THEN PRINT : PRINT " IS "; : N = FN N(0) : PRINT D(N); : H = 15 : FOR N = N TO O STEP 0: IF N < > O THEN P = PREVIOUS(N): PRINT TAB(H)CHR$(43+18*(h=15));TAB(H+2)PC(N); :N = P: H=H+5: NEXT N
|
||||
510 NEXT I
|
||||
600 DATA 7,A-B
|
||||
610 DATA 9,A-C
|
||||
620 DATA 14,A-F
|
||||
630 DATA 10,B-C
|
||||
640 DATA 15,B-D
|
||||
650 DATA 11,C-D
|
||||
660 DATA 2,C-F
|
||||
670 DATA 6,D-E
|
||||
680 DATA 9,E-F
|
||||
690 DATA
|
||||
72
Task/Dijkstras-algorithm/Arturo/dijkstras-algorithm.arturo
Normal file
72
Task/Dijkstras-algorithm/Arturo/dijkstras-algorithm.arturo
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
define :graph [vertices, neighbours][]
|
||||
|
||||
initGraph: function [edges][
|
||||
vs: []
|
||||
ns: #[]
|
||||
loop edges 'e [
|
||||
[src, dst, cost]: e
|
||||
vs: sort unique append vs src
|
||||
vs: sort unique append vs dst
|
||||
if not? key? ns src -> ns\[src]: []
|
||||
|
||||
ns\[src]: ns\[src] ++ @[@[dst, cost]]
|
||||
]
|
||||
to :graph @[vs ns]
|
||||
]
|
||||
|
||||
Inf: 1234567890
|
||||
|
||||
dijkstraPath: function [gr, fst, lst][
|
||||
dist: #[]
|
||||
prev: #[]
|
||||
result: new []
|
||||
notSeen: new gr\vertices
|
||||
loop gr\vertices 'vertex ->
|
||||
dist\[vertex]: Inf
|
||||
|
||||
dist\[fst]: 0
|
||||
|
||||
while [0 < size notSeen][
|
||||
vertex1: ""
|
||||
mindist: Inf
|
||||
loop notSeen 'vertex [
|
||||
if dist\[vertex] < mindist [
|
||||
vertex1: vertex
|
||||
mindist: dist\[vertex]
|
||||
]
|
||||
]
|
||||
if vertex1 = lst -> break
|
||||
'notSeen -- vertex1
|
||||
|
||||
if key? gr\neighbours vertex1 [
|
||||
loop gr\neighbours\[vertex1] 'v [
|
||||
[vertex2, cost]: v
|
||||
|
||||
if contains? notSeen vertex2 [
|
||||
altdist: dist\[vertex1] + cost
|
||||
if altdist < dist\[vertex2][
|
||||
dist\[vertex2]: altdist
|
||||
prev\[vertex2]: vertex1
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
vertex: lst
|
||||
while [not? empty? vertex][
|
||||
'result ++ vertex
|
||||
vertex: (key? prev vertex)? -> prev\[vertex] -> null
|
||||
]
|
||||
reverse 'result
|
||||
return result
|
||||
]
|
||||
|
||||
graph: initGraph [
|
||||
["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]
|
||||
]
|
||||
|
||||
print ["Shortest path from 'a' to 'e': " join.with:" -> " dijkstraPath graph "a" "e"]
|
||||
print ["Shortest path from 'a' to 'f': " join.with:" -> " dijkstraPath graph "a" "f"]
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
Dijkstra(data, start){
|
||||
nodes := [], dist := [], Distance := [], dist := [], prev := [], Q := [], min := "x"
|
||||
for each, line in StrSplit(data, "`n" , "`r")
|
||||
field := StrSplit(line,"`t"), nodes[field.1] := 1, nodes[field.2] := 1
|
||||
, Distance[field.1,field.2] := field.3, Distance[field.2,field.1] := field.3
|
||||
dist[start] := 0, prev[start] := ""
|
||||
|
||||
for node in nodes {
|
||||
if (node <> start)
|
||||
dist[node] := "x"
|
||||
, prev[node] := ""
|
||||
Q[node] := 1
|
||||
}
|
||||
|
||||
while % ObjCount(Q) {
|
||||
u := MinDist(Q, dist).2
|
||||
for node, val in Q
|
||||
if (node = u) {
|
||||
q.Remove(node)
|
||||
break
|
||||
}
|
||||
|
||||
for v, length in Distance[u] {
|
||||
alt := dist[u] + length
|
||||
if (alt < dist[v])
|
||||
dist[v] := alt
|
||||
, prev[v] := u
|
||||
}
|
||||
}
|
||||
return [dist, prev]
|
||||
}
|
||||
;-----------------------------------------------
|
||||
MinDist(Q, dist){
|
||||
for node , val in Q
|
||||
if A_Index=1
|
||||
min := dist[node], minNode := node
|
||||
else
|
||||
min := min < dist[node] ? min : dist[node] , minNode := min < dist[node] ? minNode : node
|
||||
return [min,minNode]
|
||||
}
|
||||
ObjCount(Obj){
|
||||
for key, val in Obj
|
||||
count := A_Index
|
||||
return count
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
data =
|
||||
(
|
||||
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
|
||||
)
|
||||
|
||||
nodes:=[], Distance := []
|
||||
for each, line in StrSplit(data, "`n" , "`r")
|
||||
field := StrSplit(line,"`t"), nodes[field.1] := 1, nodes[field.2] := 1
|
||||
, Distance[field.1,field.2] := field.3 , Distance[field.2,field.1] := field.3
|
||||
|
||||
for node, v in nodes
|
||||
nodeList .= (nodeList?"|":"") node (A_Index=1?"|":"")
|
||||
|
||||
Gui, add, Text,, From:
|
||||
Gui, add, Text, x200 yp, To:
|
||||
Gui, add, DDL, xs vFrom gSubmit, % nodeList
|
||||
Gui, add, DDL, x200 yp vTo gSubmit, % nodeList
|
||||
Gui, add, ListView, xs w340 r6, From|>|To|Distance
|
||||
Gui, add, Text, vT1 xs w340 r1
|
||||
Gui, +AlwaysOnTop
|
||||
Gui, show
|
||||
Loop 4
|
||||
LV_ModifyCol(A_Index, "80 Center")
|
||||
|
||||
Submit:
|
||||
Gui, Submit, NoHide
|
||||
GuiControl, , T1, % ""
|
||||
LV_Delete()
|
||||
if !(From && To) || (From = To)
|
||||
return
|
||||
res := Dijkstra(data, From) , xTo := xFrom := DirectFlight := "" , origin := to
|
||||
GuiControl, , T1, no routing found
|
||||
if !res[1, To] ; no possible route
|
||||
return
|
||||
|
||||
Routing:
|
||||
Loop % objCount(nodes)
|
||||
for xTo , xFrom in res.2
|
||||
if (xTo = To)
|
||||
{
|
||||
LV_Insert(1,"", xFrom, ">" , xTo, Distance[xFrom , xTo]), To := xFrom
|
||||
if (xFrom = From)
|
||||
break, Routing
|
||||
}
|
||||
GuiControl, , T1, % "Total distance = " res.1[origin] . DirectFlight
|
||||
return
|
||||
|
||||
esc::
|
||||
GuiClose:
|
||||
ExitApp
|
||||
return
|
||||
121
Task/Dijkstras-algorithm/C++/dijkstras-algorithm-1.cpp
Normal file
121
Task/Dijkstras-algorithm/C++/dijkstras-algorithm-1.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <limits> // for numeric_limits
|
||||
|
||||
#include <set>
|
||||
#include <utility> // for pair
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
typedef int vertex_t;
|
||||
typedef double weight_t;
|
||||
|
||||
const weight_t max_weight = std::numeric_limits<double>::infinity();
|
||||
|
||||
struct neighbor {
|
||||
vertex_t target;
|
||||
weight_t weight;
|
||||
neighbor(vertex_t arg_target, weight_t arg_weight)
|
||||
: target(arg_target), weight(arg_weight) { }
|
||||
};
|
||||
|
||||
typedef std::vector<std::vector<neighbor> > adjacency_list_t;
|
||||
|
||||
|
||||
void DijkstraComputePaths(vertex_t source,
|
||||
const adjacency_list_t &adjacency_list,
|
||||
std::vector<weight_t> &min_distance,
|
||||
std::vector<vertex_t> &previous)
|
||||
{
|
||||
int n = adjacency_list.size();
|
||||
min_distance.clear();
|
||||
min_distance.resize(n, max_weight);
|
||||
min_distance[source] = 0;
|
||||
previous.clear();
|
||||
previous.resize(n, -1);
|
||||
std::set<std::pair<weight_t, vertex_t> > vertex_queue;
|
||||
vertex_queue.insert(std::make_pair(min_distance[source], source));
|
||||
|
||||
while (!vertex_queue.empty())
|
||||
{
|
||||
weight_t dist = vertex_queue.begin()->first;
|
||||
vertex_t u = vertex_queue.begin()->second;
|
||||
vertex_queue.erase(vertex_queue.begin());
|
||||
|
||||
// Visit each edge exiting u
|
||||
const std::vector<neighbor> &neighbors = adjacency_list[u];
|
||||
for (std::vector<neighbor>::const_iterator neighbor_iter = neighbors.begin();
|
||||
neighbor_iter != neighbors.end();
|
||||
neighbor_iter++)
|
||||
{
|
||||
vertex_t v = neighbor_iter->target;
|
||||
weight_t weight = neighbor_iter->weight;
|
||||
weight_t distance_through_u = dist + weight;
|
||||
if (distance_through_u < min_distance[v]) {
|
||||
vertex_queue.erase(std::make_pair(min_distance[v], v));
|
||||
|
||||
min_distance[v] = distance_through_u;
|
||||
previous[v] = u;
|
||||
vertex_queue.insert(std::make_pair(min_distance[v], v));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::list<vertex_t> DijkstraGetShortestPathTo(
|
||||
vertex_t vertex, const std::vector<vertex_t> &previous)
|
||||
{
|
||||
std::list<vertex_t> path;
|
||||
for ( ; vertex != -1; vertex = previous[vertex])
|
||||
path.push_front(vertex);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// remember to insert edges both ways for an undirected graph
|
||||
adjacency_list_t adjacency_list(6);
|
||||
// 0 = a
|
||||
adjacency_list[0].push_back(neighbor(1, 7));
|
||||
adjacency_list[0].push_back(neighbor(2, 9));
|
||||
adjacency_list[0].push_back(neighbor(5, 14));
|
||||
// 1 = b
|
||||
adjacency_list[1].push_back(neighbor(0, 7));
|
||||
adjacency_list[1].push_back(neighbor(2, 10));
|
||||
adjacency_list[1].push_back(neighbor(3, 15));
|
||||
// 2 = c
|
||||
adjacency_list[2].push_back(neighbor(0, 9));
|
||||
adjacency_list[2].push_back(neighbor(1, 10));
|
||||
adjacency_list[2].push_back(neighbor(3, 11));
|
||||
adjacency_list[2].push_back(neighbor(5, 2));
|
||||
// 3 = d
|
||||
adjacency_list[3].push_back(neighbor(1, 15));
|
||||
adjacency_list[3].push_back(neighbor(2, 11));
|
||||
adjacency_list[3].push_back(neighbor(4, 6));
|
||||
// 4 = e
|
||||
adjacency_list[4].push_back(neighbor(3, 6));
|
||||
adjacency_list[4].push_back(neighbor(5, 9));
|
||||
// 5 = f
|
||||
adjacency_list[5].push_back(neighbor(0, 14));
|
||||
adjacency_list[5].push_back(neighbor(2, 2));
|
||||
adjacency_list[5].push_back(neighbor(4, 9));
|
||||
|
||||
std::vector<weight_t> min_distance;
|
||||
std::vector<vertex_t> previous;
|
||||
DijkstraComputePaths(0, adjacency_list, min_distance, previous);
|
||||
std::cout << "Distance from 0 to 4: " << min_distance[4] << std::endl;
|
||||
std::list<vertex_t> path = DijkstraGetShortestPathTo(4, previous);
|
||||
std::cout << "Path : ";
|
||||
std::copy(path.begin(), path.end(), std::ostream_iterator<vertex_t>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
128
Task/Dijkstras-algorithm/C++/dijkstras-algorithm-2.cpp
Normal file
128
Task/Dijkstras-algorithm/C++/dijkstras-algorithm-2.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <limits> // for numeric_limits
|
||||
|
||||
#include <queue>
|
||||
#include <utility> // for pair
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
typedef int vertex_t;
|
||||
typedef double weight_t;
|
||||
|
||||
const weight_t max_weight = std::numeric_limits<double>::infinity();
|
||||
|
||||
struct neighbor {
|
||||
vertex_t target;
|
||||
weight_t weight;
|
||||
neighbor(vertex_t arg_target, weight_t arg_weight)
|
||||
: target(arg_target), weight(arg_weight) { }
|
||||
};
|
||||
|
||||
typedef std::vector<std::vector<neighbor> > adjacency_list_t;
|
||||
typedef std::pair<weight_t, vertex_t> weight_vertex_pair_t;
|
||||
|
||||
void DijkstraComputePaths(vertex_t source,
|
||||
const adjacency_list_t &adjacency_list,
|
||||
std::vector<weight_t> &min_distance,
|
||||
std::vector<vertex_t> &previous)
|
||||
{
|
||||
int n = adjacency_list.size();
|
||||
min_distance.clear();
|
||||
min_distance.resize(n, max_weight);
|
||||
min_distance[source] = 0;
|
||||
previous.clear();
|
||||
previous.resize(n, -1);
|
||||
// we use greater instead of less to turn max-heap into min-heap
|
||||
std::priority_queue<weight_vertex_pair_t,
|
||||
std::vector<weight_vertex_pair_t>,
|
||||
std::greater<weight_vertex_pair_t> > vertex_queue;
|
||||
vertex_queue.push(std::make_pair(min_distance[source], source));
|
||||
|
||||
while (!vertex_queue.empty())
|
||||
{
|
||||
weight_t dist = vertex_queue.top().first;
|
||||
vertex_t u = vertex_queue.top().second;
|
||||
vertex_queue.pop();
|
||||
|
||||
// Because we leave old copies of the vertex in the priority queue
|
||||
// (with outdated higher distances), we need to ignore it when we come
|
||||
// across it again, by checking its distance against the minimum distance
|
||||
if (dist > min_distance[u])
|
||||
continue;
|
||||
|
||||
// Visit each edge exiting u
|
||||
const std::vector<neighbor> &neighbors = adjacency_list[u];
|
||||
for (std::vector<neighbor>::const_iterator neighbor_iter = neighbors.begin();
|
||||
neighbor_iter != neighbors.end();
|
||||
neighbor_iter++)
|
||||
{
|
||||
vertex_t v = neighbor_iter->target;
|
||||
weight_t weight = neighbor_iter->weight;
|
||||
weight_t distance_through_u = dist + weight;
|
||||
if (distance_through_u < min_distance[v]) {
|
||||
min_distance[v] = distance_through_u;
|
||||
previous[v] = u;
|
||||
vertex_queue.push(std::make_pair(min_distance[v], v));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::list<vertex_t> DijkstraGetShortestPathTo(
|
||||
vertex_t vertex, const std::vector<vertex_t> &previous)
|
||||
{
|
||||
std::list<vertex_t> path;
|
||||
for ( ; vertex != -1; vertex = previous[vertex])
|
||||
path.push_front(vertex);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// remember to insert edges both ways for an undirected graph
|
||||
adjacency_list_t adjacency_list(6);
|
||||
// 0 = a
|
||||
adjacency_list[0].push_back(neighbor(1, 7));
|
||||
adjacency_list[0].push_back(neighbor(2, 9));
|
||||
adjacency_list[0].push_back(neighbor(5, 14));
|
||||
// 1 = b
|
||||
adjacency_list[1].push_back(neighbor(0, 7));
|
||||
adjacency_list[1].push_back(neighbor(2, 10));
|
||||
adjacency_list[1].push_back(neighbor(3, 15));
|
||||
// 2 = c
|
||||
adjacency_list[2].push_back(neighbor(0, 9));
|
||||
adjacency_list[2].push_back(neighbor(1, 10));
|
||||
adjacency_list[2].push_back(neighbor(3, 11));
|
||||
adjacency_list[2].push_back(neighbor(5, 2));
|
||||
// 3 = d
|
||||
adjacency_list[3].push_back(neighbor(1, 15));
|
||||
adjacency_list[3].push_back(neighbor(2, 11));
|
||||
adjacency_list[3].push_back(neighbor(4, 6));
|
||||
// 4 = e
|
||||
adjacency_list[4].push_back(neighbor(3, 6));
|
||||
adjacency_list[4].push_back(neighbor(5, 9));
|
||||
// 5 = f
|
||||
adjacency_list[5].push_back(neighbor(0, 14));
|
||||
adjacency_list[5].push_back(neighbor(2, 2));
|
||||
adjacency_list[5].push_back(neighbor(4, 9));
|
||||
|
||||
std::vector<weight_t> min_distance;
|
||||
std::vector<vertex_t> previous;
|
||||
DijkstraComputePaths(0, adjacency_list, min_distance, previous);
|
||||
std::cout << "Distance from 0 to 4: " << min_distance[4] << std::endl;
|
||||
std::list<vertex_t> path = DijkstraGetShortestPathTo(4, previous);
|
||||
std::cout << "Path : ";
|
||||
std::copy(path.begin(), path.end(), std::ostream_iterator<vertex_t>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
138
Task/Dijkstras-algorithm/C-sharp/dijkstras-algorithm.cs
Normal file
138
Task/Dijkstras-algorithm/C-sharp/dijkstras-algorithm.cs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
using static System.Linq.Enumerable;
|
||||
using static System.String;
|
||||
using static System.Console;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using EdgeList = System.Collections.Generic.List<(int node, double weight)>;
|
||||
|
||||
public static class Dijkstra
|
||||
{
|
||||
public static void Main() {
|
||||
Graph graph = new Graph(6);
|
||||
Func<char, int> id = c => c - 'a';
|
||||
Func<int , char> name = i => (char)(i + 'a');
|
||||
foreach (var (start, end, cost) in new [] {
|
||||
('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),
|
||||
}) {
|
||||
graph.AddEdge(id(start), id(end), cost);
|
||||
}
|
||||
|
||||
var path = graph.FindPath(id('a'));
|
||||
for (int d = id('b'); d <= id('f'); d++) {
|
||||
WriteLine(Join(" -> ", Path(id('a'), d).Select(p => $"{name(p.node)}({p.distance})").Reverse()));
|
||||
}
|
||||
|
||||
IEnumerable<(double distance, int node)> Path(int start, int destination) {
|
||||
yield return (path[destination].distance, destination);
|
||||
for (int i = destination; i != start; i = path[i].prev) {
|
||||
yield return (path[path[i].prev].distance, path[i].prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed class Graph
|
||||
{
|
||||
private readonly List<EdgeList> adjacency;
|
||||
|
||||
public Graph(int vertexCount) => adjacency = Range(0, vertexCount).Select(v => new EdgeList()).ToList();
|
||||
|
||||
public int Count => adjacency.Count;
|
||||
public bool HasEdge(int s, int e) => adjacency[s].Any(p => p.node == e);
|
||||
public bool RemoveEdge(int s, int e) => adjacency[s].RemoveAll(p => p.node == e) > 0;
|
||||
|
||||
public bool AddEdge(int s, int e, double weight) {
|
||||
if (HasEdge(s, e)) return false;
|
||||
adjacency[s].Add((e, weight));
|
||||
return true;
|
||||
}
|
||||
|
||||
public (double distance, int prev)[] FindPath(int start) {
|
||||
var info = Range(0, adjacency.Count).Select(i => (distance: double.PositiveInfinity, prev: i)).ToArray();
|
||||
info[start].distance = 0;
|
||||
var visited = new System.Collections.BitArray(adjacency.Count);
|
||||
|
||||
var heap = new Heap<(int node, double distance)>((a, b) => a.distance.CompareTo(b.distance));
|
||||
heap.Push((start, 0));
|
||||
while (heap.Count > 0) {
|
||||
var current = heap.Pop();
|
||||
if (visited[current.node]) continue;
|
||||
var edges = adjacency[current.node];
|
||||
for (int n = 0; n < edges.Count; n++) {
|
||||
int v = edges[n].node;
|
||||
if (visited[v]) continue;
|
||||
double alt = info[current.node].distance + edges[n].weight;
|
||||
if (alt < info[v].distance) {
|
||||
info[v] = (alt, current.node);
|
||||
heap.Push((v, alt));
|
||||
}
|
||||
}
|
||||
visited[current.node] = true;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed class Heap<T>
|
||||
{
|
||||
private readonly IComparer<T> comparer;
|
||||
private readonly List<T> list = new List<T> { default };
|
||||
|
||||
public Heap() : this(default(IComparer<T>)) { }
|
||||
|
||||
public Heap(IComparer<T> comparer) {
|
||||
this.comparer = comparer ?? Comparer<T>.Default;
|
||||
}
|
||||
|
||||
public Heap(Comparison<T> comparison) : this(Comparer<T>.Create(comparison)) { }
|
||||
|
||||
public int Count => list.Count - 1;
|
||||
|
||||
public void Push(T element) {
|
||||
list.Add(element);
|
||||
SiftUp(list.Count - 1);
|
||||
}
|
||||
|
||||
public T Pop() {
|
||||
T result = list[1];
|
||||
list[1] = list[list.Count - 1];
|
||||
list.RemoveAt(list.Count - 1);
|
||||
SiftDown(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int Parent(int i) => i / 2;
|
||||
private static int Left(int i) => i * 2;
|
||||
private static int Right(int i) => i * 2 + 1;
|
||||
|
||||
private void SiftUp(int i) {
|
||||
while (i > 1) {
|
||||
int parent = Parent(i);
|
||||
if (comparer.Compare(list[i], list[parent]) > 0) return;
|
||||
(list[parent], list[i]) = (list[i], list[parent]);
|
||||
i = parent;
|
||||
}
|
||||
}
|
||||
|
||||
private void SiftDown(int i) {
|
||||
for (int left = Left(i); left < list.Count; left = Left(i)) {
|
||||
int smallest = comparer.Compare(list[left], list[i]) <= 0 ? left : i;
|
||||
int right = Right(i);
|
||||
if (right < list.Count && comparer.Compare(list[right], list[smallest]) <= 0) smallest = right;
|
||||
if (smallest == i) return;
|
||||
(list[i], list[smallest]) = (list[smallest], list[i]);
|
||||
i = smallest;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
180
Task/Dijkstras-algorithm/C/dijkstras-algorithm.c
Normal file
180
Task/Dijkstras-algorithm/C/dijkstras-algorithm.c
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef struct {
|
||||
int vertex;
|
||||
int weight;
|
||||
} edge_t;
|
||||
|
||||
typedef struct {
|
||||
edge_t **edges;
|
||||
int edges_len;
|
||||
int edges_size;
|
||||
int dist;
|
||||
int prev;
|
||||
int visited;
|
||||
} vertex_t;
|
||||
|
||||
typedef struct {
|
||||
vertex_t **vertices;
|
||||
int vertices_len;
|
||||
int vertices_size;
|
||||
} graph_t;
|
||||
|
||||
typedef struct {
|
||||
int *data;
|
||||
int *prio;
|
||||
int *index;
|
||||
int len;
|
||||
int size;
|
||||
} heap_t;
|
||||
|
||||
void add_vertex (graph_t *g, int i) {
|
||||
if (g->vertices_size < i + 1) {
|
||||
int size = g->vertices_size * 2 > i ? g->vertices_size * 2 : i + 4;
|
||||
g->vertices = realloc(g->vertices, size * sizeof (vertex_t *));
|
||||
for (int j = g->vertices_size; j < size; j++)
|
||||
g->vertices[j] = NULL;
|
||||
g->vertices_size = size;
|
||||
}
|
||||
if (!g->vertices[i]) {
|
||||
g->vertices[i] = calloc(1, sizeof (vertex_t));
|
||||
g->vertices_len++;
|
||||
}
|
||||
}
|
||||
|
||||
void add_edge (graph_t *g, int a, int b, int w) {
|
||||
a = a - 'a';
|
||||
b = b - 'a';
|
||||
add_vertex(g, a);
|
||||
add_vertex(g, b);
|
||||
vertex_t *v = g->vertices[a];
|
||||
if (v->edges_len >= v->edges_size) {
|
||||
v->edges_size = v->edges_size ? v->edges_size * 2 : 4;
|
||||
v->edges = realloc(v->edges, v->edges_size * sizeof (edge_t *));
|
||||
}
|
||||
edge_t *e = calloc(1, sizeof (edge_t));
|
||||
e->vertex = b;
|
||||
e->weight = w;
|
||||
v->edges[v->edges_len++] = e;
|
||||
}
|
||||
|
||||
heap_t *create_heap (int n) {
|
||||
heap_t *h = calloc(1, sizeof (heap_t));
|
||||
h->data = calloc(n + 1, sizeof (int));
|
||||
h->prio = calloc(n + 1, sizeof (int));
|
||||
h->index = calloc(n, sizeof (int));
|
||||
return h;
|
||||
}
|
||||
|
||||
void push_heap (heap_t *h, int v, int p) {
|
||||
int i = h->index[v] == 0 ? ++h->len : h->index[v];
|
||||
int j = i / 2;
|
||||
while (i > 1) {
|
||||
if (h->prio[j] < p)
|
||||
break;
|
||||
h->data[i] = h->data[j];
|
||||
h->prio[i] = h->prio[j];
|
||||
h->index[h->data[i]] = i;
|
||||
i = j;
|
||||
j = j / 2;
|
||||
}
|
||||
h->data[i] = v;
|
||||
h->prio[i] = p;
|
||||
h->index[v] = i;
|
||||
}
|
||||
|
||||
int min (heap_t *h, int i, int j, int k) {
|
||||
int m = i;
|
||||
if (j <= h->len && h->prio[j] < h->prio[m])
|
||||
m = j;
|
||||
if (k <= h->len && h->prio[k] < h->prio[m])
|
||||
m = k;
|
||||
return m;
|
||||
}
|
||||
|
||||
int pop_heap (heap_t *h) {
|
||||
int v = h->data[1];
|
||||
int i = 1;
|
||||
while (1) {
|
||||
int j = min(h, h->len, 2 * i, 2 * i + 1);
|
||||
if (j == h->len)
|
||||
break;
|
||||
h->data[i] = h->data[j];
|
||||
h->prio[i] = h->prio[j];
|
||||
h->index[h->data[i]] = i;
|
||||
i = j;
|
||||
}
|
||||
h->data[i] = h->data[h->len];
|
||||
h->prio[i] = h->prio[h->len];
|
||||
h->index[h->data[i]] = i;
|
||||
h->len--;
|
||||
return v;
|
||||
}
|
||||
|
||||
void dijkstra (graph_t *g, int a, int b) {
|
||||
int i, j;
|
||||
a = a - 'a';
|
||||
b = b - 'a';
|
||||
for (i = 0; i < g->vertices_len; i++) {
|
||||
vertex_t *v = g->vertices[i];
|
||||
v->dist = INT_MAX;
|
||||
v->prev = 0;
|
||||
v->visited = 0;
|
||||
}
|
||||
vertex_t *v = g->vertices[a];
|
||||
v->dist = 0;
|
||||
heap_t *h = create_heap(g->vertices_len);
|
||||
push_heap(h, a, v->dist);
|
||||
while (h->len) {
|
||||
i = pop_heap(h);
|
||||
if (i == b)
|
||||
break;
|
||||
v = g->vertices[i];
|
||||
v->visited = 1;
|
||||
for (j = 0; j < v->edges_len; j++) {
|
||||
edge_t *e = v->edges[j];
|
||||
vertex_t *u = g->vertices[e->vertex];
|
||||
if (!u->visited && v->dist + e->weight <= u->dist) {
|
||||
u->prev = i;
|
||||
u->dist = v->dist + e->weight;
|
||||
push_heap(h, e->vertex, u->dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_path (graph_t *g, int i) {
|
||||
int n, j;
|
||||
vertex_t *v, *u;
|
||||
i = i - 'a';
|
||||
v = g->vertices[i];
|
||||
if (v->dist == INT_MAX) {
|
||||
printf("no path\n");
|
||||
return;
|
||||
}
|
||||
for (n = 1, u = v; u->dist; u = g->vertices[u->prev], n++)
|
||||
;
|
||||
char *path = malloc(n);
|
||||
path[n - 1] = 'a' + i;
|
||||
for (j = 0, u = v; u->dist; u = g->vertices[u->prev], j++)
|
||||
path[n - j - 2] = 'a' + u->prev;
|
||||
printf("%d %.*s\n", v->dist, n, path);
|
||||
}
|
||||
|
||||
int main () {
|
||||
graph_t *g = calloc(1, sizeof (graph_t));
|
||||
add_edge(g, 'a', 'b', 7);
|
||||
add_edge(g, 'a', 'c', 9);
|
||||
add_edge(g, 'a', 'f', 14);
|
||||
add_edge(g, 'b', 'c', 10);
|
||||
add_edge(g, 'b', 'd', 15);
|
||||
add_edge(g, 'c', 'd', 11);
|
||||
add_edge(g, 'c', 'f', 2);
|
||||
add_edge(g, 'd', 'e', 6);
|
||||
add_edge(g, 'e', 'f', 9);
|
||||
dijkstra(g, 'a', 'e');
|
||||
print_path(g, 'e');
|
||||
return 0;
|
||||
}
|
||||
192
Task/Dijkstras-algorithm/CafeOBJ/dijkstras-algorithm.cafeobj
Normal file
192
Task/Dijkstras-algorithm/CafeOBJ/dijkstras-algorithm.cafeobj
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
"
|
||||
This code works with CafeOBJ 1.5.1 and CafeOBJ 1.5.5.
|
||||
Save this file as DijkstraRosetta.cafe.
|
||||
To run the file type
|
||||
CafeOBJ> in DijkstraRosetta.cafe
|
||||
at the CafeOBJ command prompt.
|
||||
|
||||
CafeOBJ is primarily a first order specification language which can also be used as a functional programming language.
|
||||
Being first order, we make no use higher order functions such as map.
|
||||
There is a minimal library of basic types such as natural numbers, integers, floating point number, and character string.
|
||||
There are no libraries for arrays, lists, trees, graphs.
|
||||
Hence the user written list module.
|
||||
|
||||
|
||||
Input
|
||||
A directed positively weighted graph. The graph is represented as a list of 4tuples containing directed edges of the form (start, end, edgeDist,pathDist)
|
||||
The tuple (start, start,0,0) means there is zero distance from start to start.
|
||||
|
||||
Ouput
|
||||
1) a list of 4-tuples with each tuple represents a node N, its source node, length of the connecting edge to N, and the shortest distance from the some starting node to N .
|
||||
2) a list of nodes on the shortest path from a chosen start to some chosen end node.
|
||||
|
||||
Note needs a bit more work to exactly match the specified Rosetta Dijkstra task.
|
||||
"
|
||||
|
||||
-- some system settings
|
||||
-- Most important is memoization (memo) which stores the value of a function instead of recomputing it each time the function is called.
|
||||
full reset
|
||||
set step off
|
||||
set print mode :fancy
|
||||
set stats off
|
||||
set verbose off
|
||||
set quiet on
|
||||
set memo on
|
||||
|
||||
-- A module defining a simple parameterized list.
|
||||
mod! LIST(T :: TRIV) principal-sort List {
|
||||
[Elt < List ]
|
||||
op nil : -> List
|
||||
op (_:_) : List List -> List {memo assoc id: nil}
|
||||
op reverse_ : List -> List
|
||||
op head_ : List -> Elt
|
||||
var e : Elt
|
||||
var l : List
|
||||
eq reverse nil = nil .
|
||||
eq reverse (e : l) = (reverse l) : e .
|
||||
eq head e : l = e .
|
||||
}
|
||||
|
||||
|
||||
-- Main module
|
||||
mod! DIJKSTRA {
|
||||
-- We use two different list notations, one for edges the other for paths.
|
||||
|
||||
-- EdgeList : A four tuple used to store graph and paths and shortest distance
|
||||
-- start, end, edgeDist,pathDist
|
||||
pr(LIST(4TUPLE(CHARACTER,CHARACTER,INT,INT)) *{sort List -> EdgeList, op (_:_) -> (_:e_), op nil -> nilE})
|
||||
|
||||
-- PathList : A list of characters used to store final shortest path.
|
||||
pr(LIST(CHARACTER) *{sort List -> PathList, op (_:_) -> (_:p_), op nil -> nilP})
|
||||
|
||||
|
||||
|
||||
op dijkstra___ : Character EdgeList EdgeList -> EdgeList
|
||||
op exploreNeighbours___ : Character EdgeList EdgeList -> 4Tuple {memo}
|
||||
ops inf finishedI : -> Int
|
||||
op finishedC : -> Character
|
||||
op currDist__ : Character EdgeList -> Int
|
||||
op relax__ : EdgeList EdgeList -> EdgeList
|
||||
op connectedTo__ : Character EdgeList -> Bool
|
||||
op nextNode2Explore_ : EdgeList -> 4Tuple
|
||||
op connectedList___ : EdgeList Character EdgeList -> EdgeList
|
||||
op unvisitedList__ : EdgeList EdgeList -> EdgeList
|
||||
op SP___ : Character Character EdgeList -> PathList
|
||||
|
||||
|
||||
vars eD pD eD1 pD1 eD2 pD2 source : Int
|
||||
vars graph permanent xs : EdgeList
|
||||
vars t t1 t2 : 4Tuple
|
||||
vars s f z startVertex currentVertex : Character
|
||||
|
||||
|
||||
eq inf = 500 .
|
||||
eq finishedI = -1 .
|
||||
eq finishedC = 'X' .
|
||||
|
||||
-- Main dijkstra function
|
||||
eq dijkstra startVertex graph permanent =
|
||||
if
|
||||
(exploreNeighbours startVertex permanent graph) == << finishedC ; finishedC ; finishedI ; finishedI >>
|
||||
then permanent
|
||||
else
|
||||
(dijkstra startVertex graph ( ((exploreNeighbours startVertex permanent graph) :e permanent))) fi .
|
||||
|
||||
|
||||
eq exploreNeighbours startVertex permanent graph =
|
||||
(nextNode2Explore (relax (unvisitedList (connectedList graph startVertex permanent) permanent) permanent )) .
|
||||
|
||||
|
||||
|
||||
-- nextNode2Explore takes a list of records and returns a record with the minimum 4th element else finished
|
||||
eq nextNode2Explore nilE = << finishedC ; finishedC ; finishedI ; finishedI >> .
|
||||
eq nextNode2Explore (t1 :e nilE) = t1 .
|
||||
eq nextNode2Explore (t2 :e (t1 :e xs)) = if (4* t1) < (4* t2) then t1
|
||||
else
|
||||
nextNode2Explore (t2 :e xs) fi .
|
||||
|
||||
-- relaxes all edges leaving y
|
||||
eq relax nilE permanent = nilE .
|
||||
eq relax (<< s ; f ; eD ; pD >> :e xs) permanent =
|
||||
if
|
||||
(currDist s permanent) < pD
|
||||
then
|
||||
<< f ; s ; eD ; ((currDist s permanent) + eD) >> :e (relax xs permanent)
|
||||
else
|
||||
<< f ; s ; eD ; pD >> :e (relax xs permanent) fi .
|
||||
|
||||
|
||||
-- Get the current best distance for a particular vertex s.
|
||||
eq currDist s nilE = inf .
|
||||
eq currDist s (t :e permanent) = if ((1* t) == s) then (4* t ) else
|
||||
(currDist s permanent) fi .
|
||||
|
||||
|
||||
eq connectedTo z nilE = false .
|
||||
eq connectedTo z ((<< s ; f ; eD ; pD >>) :e xs) = if (s == z) then true else (connectedTo z xs) fi .
|
||||
|
||||
eq connectedList nilE s permanent = nilE .
|
||||
eq connectedList (t :e graph) s permanent = if (connectedTo s permanent) then
|
||||
(t :e (connectedList graph s permanent))
|
||||
else (connectedList graph s permanent) fi .
|
||||
|
||||
|
||||
eq unvisitedList nilE permanent = nilE .
|
||||
eq unvisitedList (t :e graph) permanent = if not(connectedTo (2* t) permanent)
|
||||
then (t :e (unvisitedList graph permanent))
|
||||
else (unvisitedList graph permanent) fi .
|
||||
|
||||
|
||||
|
||||
-- To get the shortest path from a start node to some end node we used the above dijkstra function.
|
||||
-- From a given start to a given end we need to trace the path from the finish to the start and then reverse the output.
|
||||
var eList : EdgeList
|
||||
vars currentTuple : 4Tuple
|
||||
vars start end : Character
|
||||
eq SP start end nilE = nilP .
|
||||
eq SP start end (currentTuple :e eList) = if (end == (1* currentTuple)) then
|
||||
(end :p (SP start (2* currentTuple) eList))
|
||||
else (SP start end eList) fi .
|
||||
|
||||
|
||||
-- The graph to be traversed
|
||||
op DirectedRosetta : -> EdgeList
|
||||
eq DirectedRosetta = ( << 'a' ; 'b' ; 7 ; inf >> :e
|
||||
<< 'a' ; 'c' ; 9 ; inf >> :e
|
||||
<< 'a' ; 'f' ; 14 ; inf >> :e
|
||||
<< 'b' ; 'c' ; 10 ; inf >> :e
|
||||
<< 'b' ; 'd' ; 15 ; inf >> :e
|
||||
<< 'c' ; 'd' ; 11 ; inf >> :e
|
||||
<< 'c' ; 'f' ; 2 ; inf >> :e
|
||||
<< 'd' ; 'e' ; 6 ; inf >> :e
|
||||
<< 'e' ; 'f' ; 9 ; inf >>) .
|
||||
|
||||
|
||||
-- A set of possible starting points
|
||||
ops oneStart twoStart threeStart fourStart fiveStart sixStart : -> 4Tuple
|
||||
eq oneStart = << 'a' ; 'a' ; 0 ; 0 >> .
|
||||
eq twoStart = << 'b' ; 'b' ; 0 ; 0 >> .
|
||||
eq threeStart = << 'c' ; 'c' ; 0 ; 0 >> .
|
||||
eq fourStart = << 'd' ; 'd' ; 0 ; 0 >> .
|
||||
eq fiveStart = << 'e' ; 'e' ; 0 ; 0 >> .
|
||||
eq sixStart = << 'f' ; 'f' ; 0 ; 0 >> .
|
||||
|
||||
} -- End module
|
||||
|
||||
-- We must open the module in the CafeOBJ interpreter
|
||||
open DIJKSTRA .
|
||||
--> All shortest distances starting from a(1)
|
||||
red dijkstra 'a' DirectedRosetta oneStart .
|
||||
-- Gives, where :e is the edge list separator
|
||||
-- << 'e' ; 'd' ; 6 ; 26 >> :e << 'd' ; 'c' ; 11 ; 20 >> :e << 'f' ; 'c' ; 2 ; 11 >> :e << 'c' ; 'a' ; 9 ; 9 >> :e << 'b' ; 'a' ; 7 ; 7 >>) :e << 'a' ; 'a' ; 0 ; 0 >> :EdgeList
|
||||
|
||||
--> Shortest path from a(1) to e(5)
|
||||
red reverse (SP 'a' 'e' (dijkstra 'a' DirectedRosetta oneStart)) .
|
||||
-- Gives, where :p is the path list separator
|
||||
-- 'a' :p 'c' :p 'd' :p 'e' :PathList
|
||||
|
||||
--> Shortest path from a(1) to f(6)
|
||||
red reverse (SP 'a' 'f' (dijkstra 'a' DirectedRosetta oneStart)) .
|
||||
-- Gives, where :p is the path list separator
|
||||
-- 'a' :p 'c' :p 'f':PathList
|
||||
eof
|
||||
197
Task/Dijkstras-algorithm/Clojure/dijkstras-algorithm.clj
Normal file
197
Task/Dijkstras-algorithm/Clojure/dijkstras-algorithm.clj
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
(declare neighbours
|
||||
process-neighbour
|
||||
prepare-costs
|
||||
get-next-node
|
||||
unwind-path
|
||||
all-shortest-paths)
|
||||
|
||||
|
||||
;; Main algorithm
|
||||
|
||||
|
||||
(defn dijkstra
|
||||
"Given two nodes A and B, and graph, finds shortest path from point A to point B.
|
||||
Given one node and graph, finds all shortest paths to all other nodes.
|
||||
|
||||
Graph example: {1 {2 7 3 9 6 14}
|
||||
2 {1 7 3 10 4 15}
|
||||
3 {1 9 2 10 4 11 6 2}
|
||||
4 {2 15 3 11 5 6}
|
||||
5 {6 9 4 6}
|
||||
6 {1 14 3 2 5 9}}
|
||||
^ ^ ^
|
||||
| | |
|
||||
node label | |
|
||||
neighbour label--- |
|
||||
edge cost------
|
||||
From example in Wikipedia: https://en.wikipedia.org/wiki/Dijkstra's_algorithm
|
||||
|
||||
Output example: [20 [1 3 6 5]]
|
||||
^ ^
|
||||
| |
|
||||
shortest path cost |
|
||||
shortest path---"
|
||||
([a b graph]
|
||||
(loop [costs (prepare-costs a graph)
|
||||
unvisited (set (keys graph))]
|
||||
(let [current-node (get-next-node costs unvisited)
|
||||
current-cost (first (costs current-node))]
|
||||
(cond (nil? current-node)
|
||||
(all-shortest-paths a costs)
|
||||
|
||||
(= current-node b)
|
||||
[current-cost (unwind-path a b costs)]
|
||||
|
||||
:else
|
||||
(recur (reduce (partial process-neighbour
|
||||
current-node
|
||||
current-cost)
|
||||
costs
|
||||
(filter (comp unvisited first)
|
||||
(neighbours current-node graph costs)))
|
||||
(disj unvisited current-node))))))
|
||||
([a graph] (dijkstra a nil graph)))
|
||||
|
||||
|
||||
;; Implementation details
|
||||
|
||||
|
||||
(defn prepare-costs
|
||||
"For given start node A ang graph prepare map of costs to start with
|
||||
(assign maximum value for all nodes and zero for starting one).
|
||||
Also save info about most advantageous parent.
|
||||
Example output: {2 [2147483647 7], 6 [2147483647 14]}
|
||||
^ ^ ^
|
||||
| | |
|
||||
node | |
|
||||
cost----- |
|
||||
parent---------------"
|
||||
[start graph]
|
||||
(assoc (zipmap (keys graph)
|
||||
(repeat [Integer/MAX_VALUE nil]))
|
||||
start [0 start]))
|
||||
|
||||
|
||||
(defn neighbours
|
||||
"Get given node's neighbours along with their own costs and costs of corresponding edges.
|
||||
Example output is: {1 [7 10] 2 [4 15]}
|
||||
^ ^ ^
|
||||
| | |
|
||||
neighbour node label | |
|
||||
neighbour cost --- |
|
||||
edge cost ------"
|
||||
[node graph costs]
|
||||
(->> (graph node)
|
||||
(map (fn [[neighbour edge-cost]]
|
||||
[neighbour [(first (costs neighbour)) edge-cost]]))
|
||||
(into {})))
|
||||
|
||||
|
||||
(defn process-neighbour
|
||||
[parent
|
||||
parent-cost
|
||||
costs
|
||||
[neighbour [old-cost edge-cost]]]
|
||||
(let [new-cost (+ parent-cost edge-cost)]
|
||||
(if (< new-cost old-cost)
|
||||
(assoc costs
|
||||
neighbour
|
||||
[new-cost parent])
|
||||
costs)))
|
||||
|
||||
|
||||
(defn get-next-node [costs unvisited]
|
||||
(->> costs
|
||||
(filter (comp unvisited first))
|
||||
(sort-by (comp first second))
|
||||
ffirst))
|
||||
|
||||
|
||||
(defn unwind-path
|
||||
"Restore path from A to B based on costs data"
|
||||
[a b costs]
|
||||
(letfn [(f [a b costs]
|
||||
(when-not (= a b)
|
||||
(cons b (f a (second (costs b)) costs))))]
|
||||
(cons a (reverse (f a b costs)))))
|
||||
|
||||
|
||||
(defn all-shortest-paths
|
||||
"Get shortest paths for all nodes, along with their costs"
|
||||
[start costs]
|
||||
(let [paths (->> (keys costs)
|
||||
(remove #{start})
|
||||
(map (fn [n] [n (unwind-path start n costs)])))]
|
||||
(into (hash-map)
|
||||
(map (fn [[n p]]
|
||||
[n [(first (costs n)) p]])
|
||||
paths))))
|
||||
|
||||
|
||||
;; Utils
|
||||
|
||||
|
||||
(require '[clojure.pprint :refer [print-table]])
|
||||
|
||||
|
||||
(defn print-solution [solution]
|
||||
(print-table
|
||||
(map (fn [[node [cost path]]]
|
||||
{'node node 'cost cost 'path path})
|
||||
solution)))
|
||||
|
||||
|
||||
;; Solutions
|
||||
|
||||
|
||||
;; Task 1. Implement a version of Dijkstra's algorithm that outputs a set of edges depicting the shortest path to each reachable node from an origin.
|
||||
|
||||
;; see above
|
||||
|
||||
|
||||
;; Task 2. Run your program with the following directed graph starting at node a.
|
||||
|
||||
;; Edges
|
||||
;; Start End Cost
|
||||
;; 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
|
||||
|
||||
(def rosetta-graph
|
||||
'{a {b 7 c 9 f 14}
|
||||
b {c 10 d 15}
|
||||
c {d 11 f 2}
|
||||
d {e 6}
|
||||
e {f 9}
|
||||
f {}})
|
||||
|
||||
(def task-2-solution
|
||||
(dijkstra 'a rosetta-graph))
|
||||
|
||||
(print-solution task-2-solution)
|
||||
|
||||
;; Output:
|
||||
;; | node | cost | path |
|
||||
;; |------+------+-----------|
|
||||
;; | b | 7 | (a b) |
|
||||
;; | c | 9 | (a c) |
|
||||
;; | d | 20 | (a c d) |
|
||||
;; | e | 26 | (a c d e) |
|
||||
;; | f | 11 | (a c f) |
|
||||
|
||||
|
||||
;; Task 3. Write a program which interprets the output from the above and use it to output the shortest path from node a to nodes e and f
|
||||
|
||||
(print-solution (select-keys task-2-solution '[e f]))
|
||||
|
||||
;; Output:
|
||||
;; | node | cost | path |
|
||||
;; |------+------+-----------|
|
||||
;; | e | 26 | (a c d e) |
|
||||
;; | f | 11 | (a c f) |
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
100 NV=0: REM NUMBER OF VERTICES
|
||||
110 READ N$:IF N$<>"" THEN NV=NV+1:GOTO 110
|
||||
120 NE=0: REM NUMBER OF EDGES
|
||||
130 READ N1:IF N1 >= 0 THEN READ N2,W:NE=NE+1:GOTO 130
|
||||
140 DIM VN$(NV-1),VD(NV-1,2): REM VERTEX NAMES AND DATA
|
||||
150 DIM ED(NE-1,2): REM EDGE DATA
|
||||
160 RESTORE
|
||||
170 FOR I=0 TO NV-1
|
||||
180 : READ VN$(I): REM VERTEX NAME
|
||||
190 : VD(I,0) = -1: REM DISTANCE = INFINITY
|
||||
200 : VD(I,1) = 0: REM NOT YET VISITED
|
||||
210 : VD(I,2) = -1: REM NO PREV VERTEX YET
|
||||
220 NEXT I
|
||||
230 READ N$: REM SKIP SENTINEL
|
||||
240 FOR I=0 TO NE-1
|
||||
250 : READ ED(I,0),ED(I,1),ED(I,2): REM EDGE FROM, TO, WEIGHT
|
||||
260 NEXT I
|
||||
270 READ N1: REM SKIP SENTINEL
|
||||
280 READ O: REM ORIGIN VERTEX
|
||||
290 :
|
||||
300 REM BEGIN DIJKSTRA'S
|
||||
310 VD(O,0) = 0: REM DISTANCE TO ORIGIN IS 0
|
||||
320 CV = 0: REM CURRENT VERTEX IS ORIGIN
|
||||
330 FOR I=0 TO NE-1
|
||||
340 : IF ED(I,0)<>CV THEN 390: REM SKIP EDGES NOT FROM CURRENT
|
||||
350 : N=ED(I,1): REM NEIGHBOR VERTEX
|
||||
360 : D=VD(CV,0) + ED(I,2): REM TOTAL DISTANCE TO NEIGHBOR THROUGH THIS PATH
|
||||
370 : REM IF PATH THRU CV < DISTANCE, UPDATE DISTANCE AND PREV VERTEX
|
||||
380 : IF (VD(N,0)=-1) OR (D<VD(N,0)) THEN VD(N,0) = D:VD(N,2)=CV
|
||||
390 NEXT I
|
||||
400 VD(CV,1)=1: REM CURRENT VERTEX HAS BEEN VISITED
|
||||
410 MV=-1: REM VERTEX WITH MINIMUM DISTANCE SEEN
|
||||
420 FOR I=0 TO NV-1
|
||||
430 : IF VD(I,1) THEN 470: REM SKIP VISITED VERTICES
|
||||
440 : REM IF THIS IS THE SMALLEST DISTANCE SEEN, REMEMBER IT
|
||||
450 : MD=-1:IF MV > -1 THEN MD=VD(MV,0)
|
||||
460 : IF ( VD(I,0)<>-1 ) AND ( ( MD=-1 ) OR ( VD(I,0)<MD ) ) THEN MV=I
|
||||
470 NEXT I
|
||||
480 IF MD=-1 THEN 510: REM END IF ALL VERTICES VISITED OR AT INFINITY
|
||||
490 CV=MV
|
||||
500 GOTO 330
|
||||
510 PRINT "SHORTEST PATH TO EACH VERTEX FROM "VN$(O)":";CHR$(13)
|
||||
520 FOR I=0 TO NV-1
|
||||
530 : IF I=0 THEN 600
|
||||
540 : PRINT VN$(I)":"VD(I,0)"(";
|
||||
550 : IF VD(I,0)=-1 THEN 600
|
||||
560 : N=I
|
||||
570 : PRINT VN$(N);
|
||||
580 : IF N<>O THEN PRINT "←";:N=VD(N,2):GOTO 570
|
||||
590 : PRINT ")"
|
||||
600 NEXT I
|
||||
610 DATA A,B,C,D,E,F,""
|
||||
620 DATA 0,1,7
|
||||
630 DATA 0,2,9
|
||||
640 DATA 0,5,14
|
||||
650 DATA 1,2,10
|
||||
660 DATA 1,3,15
|
||||
670 DATA 2,3,11
|
||||
680 DATA 2,5,2
|
||||
690 DATA 3,4,6
|
||||
700 DATA 4,5,9
|
||||
710 DATA -1
|
||||
720 DATA 0
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
(defparameter *w* '((a (a b . 7) (a c . 9) (a f . 14))
|
||||
(b (b c . 10) (b d . 15))
|
||||
(c (c d . 11) (c f . 2))
|
||||
(d (d e . 6))
|
||||
(e (e f . 9))))
|
||||
|
||||
(defvar *r* nil)
|
||||
|
||||
(defun dijkstra-short-path (i g)
|
||||
(setf *r* nil) (paths i g 0 `(,i))
|
||||
(car (sort *r* #'< :key #'cadr)))
|
||||
|
||||
(defun paths (c g z v)
|
||||
(if (eql c g) (push `(,(reverse v) ,z) *r*)
|
||||
(loop for a in (nodes c) for b = (cadr a) do
|
||||
(unless (member b v)
|
||||
(paths b g (+ (cddr a) z) (cons b v))))))
|
||||
|
||||
(defun nodes (c)
|
||||
(sort (cdr (assoc c *w*)) #'< :key #'cddr))
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
(defvar *r* nil)
|
||||
|
||||
(defun dijkstra-short-paths (z w)
|
||||
(loop for (a b) in (loop for v on z nconc
|
||||
(loop for e in (cdr v)
|
||||
collect `(,(car v) ,e)))
|
||||
do (setf *r* nil) (paths w a b 0 `(,a))
|
||||
(format t "~{Path: ~A Distance: ~A~}~%"
|
||||
(car (sort *r* #'< :key #'cadr)))))
|
||||
|
||||
(defun paths (w c g z v)
|
||||
(if (eql c g) (push `(,(reverse v) ,z) *r*)
|
||||
(loop for a in (sort (cdr (assoc c w)) #'< :key #'cddr)
|
||||
for b = (cadr a) do (unless (member b v)
|
||||
(paths w b g (+ (cddr a) z)
|
||||
(cons b v))))))
|
||||
83
Task/Dijkstras-algorithm/D/dijkstras-algorithm.d
Normal file
83
Task/Dijkstras-algorithm/D/dijkstras-algorithm.d
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import std.stdio, std.typecons, std.algorithm, std.container;
|
||||
|
||||
alias Vertex = string;
|
||||
alias Weight = int;
|
||||
|
||||
struct Neighbor {
|
||||
Vertex target;
|
||||
Weight weight;
|
||||
}
|
||||
|
||||
alias AdjacencyMap = Neighbor[][Vertex];
|
||||
|
||||
pure dijkstraComputePaths(Vertex source, Vertex target, AdjacencyMap adjacencyMap){
|
||||
Weight[Vertex] minDistance;
|
||||
Vertex[Vertex] previous;
|
||||
|
||||
foreach(v, neighs; adjacencyMap){
|
||||
minDistance[v] = Weight.max;
|
||||
foreach(n; neighs) minDistance[n.target] = Weight.max;
|
||||
}
|
||||
|
||||
minDistance[source] = 0;
|
||||
auto vertexQueue = redBlackTree(tuple(minDistance[source], source));
|
||||
|
||||
foreach(_, u; vertexQueue){
|
||||
if (u == target)
|
||||
break;
|
||||
|
||||
// Visit each edge exiting u.
|
||||
foreach(n; adjacencyMap.get(u, null)){
|
||||
const v = n.target;
|
||||
const distanceThroughU = minDistance[u] + n.weight;
|
||||
if(distanceThroughU < minDistance[v]){
|
||||
vertexQueue.removeKey(tuple(minDistance[v], v));
|
||||
minDistance[v] = distanceThroughU;
|
||||
previous[v] = u;
|
||||
vertexQueue.insert(tuple(minDistance[v], v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tuple(minDistance, previous);
|
||||
}
|
||||
|
||||
pure dijkstraGetShortestPathTo(Vertex v, Vertex[Vertex] previous){
|
||||
Vertex[] path = [v];
|
||||
|
||||
while (v in previous) {
|
||||
v = previous[v];
|
||||
if (v == path[$ - 1])
|
||||
break;
|
||||
path ~= v;
|
||||
}
|
||||
|
||||
path.reverse();
|
||||
return path;
|
||||
}
|
||||
|
||||
void main() {
|
||||
immutable arcs = [tuple("a", "b", 7),
|
||||
tuple("a", "c", 9),
|
||||
tuple("a", "f", 14),
|
||||
tuple("b", "c", 10),
|
||||
tuple("b", "d", 15),
|
||||
tuple("c", "d", 11),
|
||||
tuple("c", "f", 2),
|
||||
tuple("d", "e", 6),
|
||||
tuple("e", "f", 9)];
|
||||
|
||||
AdjacencyMap adj;
|
||||
foreach (immutable arc; arcs) {
|
||||
adj[arc[0]] ~= Neighbor(arc[1], arc[2]);
|
||||
// Add this if you want an undirected graph:
|
||||
//adj[arc[1]] ~= Neighbor(arc[0], arc[2]);
|
||||
}
|
||||
|
||||
const minDist_prev = dijkstraComputePaths("a", "e", adj);
|
||||
const minDistance = minDist_prev[0];
|
||||
const previous = minDist_prev[1];
|
||||
|
||||
writeln(`Distance from "a" to "e": `, minDistance["e"]);
|
||||
writeln("Path: ", dijkstraGetShortestPathTo("e", previous));
|
||||
}
|
||||
110
Task/Dijkstras-algorithm/Delphi/dijkstras-algorithm.delphi
Normal file
110
Task/Dijkstras-algorithm/Delphi/dijkstras-algorithm.delphi
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
program Rosetta_Dijkstra_Console;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses SysUtils; // for printing the result
|
||||
|
||||
// Conventional values (any negative values would do)
|
||||
const
|
||||
INFINITY = -1;
|
||||
NO_VERTEX = -2;
|
||||
|
||||
const
|
||||
NR_VERTICES = 6;
|
||||
|
||||
// DISTANCE_MATRIX[u, v] = length of directed edge from u to v, or -1 if no such edge exists.
|
||||
// A simple way to represent a directed graph with not many vertices.
|
||||
const DISTANCE_MATRIX : array [0..(NR_VERTICES - 1), 0..(NR_VERTICES - 1)] of integer
|
||||
= ((-1, 7, 9, -1, -1, -1),
|
||||
(-1, -1, 10, 15, -1, -1),
|
||||
(-1, -1, -1, 11, -1, 2),
|
||||
(-1, -1, -1, -1, 6, -1),
|
||||
(-1, -1, -1, -1, -1, 9),
|
||||
(-1, -1, -1, -1, -1, -1));
|
||||
|
||||
type TVertex = record
|
||||
Distance : integer; // distance from vertex 0; infinity if a path has not yet been found
|
||||
Previous : integer; // previous vertex in the path from vertex 0
|
||||
Visited : boolean; // as defined in the algorithm
|
||||
end;
|
||||
|
||||
// For distances x and y, test whether x < y, using the convention that -1 means infinity.
|
||||
function IsLess( x, y : integer) : boolean;
|
||||
begin
|
||||
result := (x <> INFINITY)
|
||||
and ( (y = INFINITY) or (x < y) );
|
||||
end;
|
||||
|
||||
// Main routine
|
||||
var
|
||||
v : array [0..NR_VERTICES - 1] of TVertex; // array of vertices
|
||||
c : integer; // index of current vertex
|
||||
j : integer; // loop counter
|
||||
trialDistance : integer;
|
||||
minDistance : integer;
|
||||
// Variables for printing the result
|
||||
p : integer;
|
||||
lineOut : string;
|
||||
begin
|
||||
// Initialize the vertices
|
||||
for j := 0 to NR_VERTICES - 1 do begin
|
||||
v[j].Distance := INFINITY;
|
||||
v[j].Previous := NO_VERTEX;
|
||||
v[j].Visited := false;
|
||||
end;
|
||||
|
||||
// Start with vertex 0 as the current vertex
|
||||
c := 0;
|
||||
v[c].Distance := 0;
|
||||
|
||||
// Main loop of Dijkstra's algorithm
|
||||
repeat
|
||||
|
||||
// Work through unvisited neighbours of the current vertex, updating them where possible.
|
||||
// "Neighbour" means the end of a directed edge from the current vertex.
|
||||
// Note that v[c].Distance is always finite.
|
||||
for j := 0 to NR_VERTICES - 1 do begin
|
||||
if (not v[j].Visited) and (DISTANCE_MATRIX[c, j] >= 0) then begin
|
||||
trialDistance := v[c].Distance + DISTANCE_MATRIX[c, j];
|
||||
if IsLess( trialDistance, v[j].Distance) then begin
|
||||
v[j].Distance := trialDistance;
|
||||
v[j].Previous := c;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// When all neighbours have been tested, mark the current vertex as visited.
|
||||
v[c].Visited := true;
|
||||
|
||||
// The new current vertex is the unvisited vertex with the smallest finite distance.
|
||||
// If there is no such vertex, the algorithm is finished.
|
||||
c := NO_VERTEX;
|
||||
minDistance := INFINITY;
|
||||
for j := 0 to NR_VERTICES - 1 do begin
|
||||
if (not v[j].Visited) and IsLess( v[j].Distance, minDistance) then begin
|
||||
minDistance := v[j].Distance;
|
||||
c := j;
|
||||
end;
|
||||
end;
|
||||
until (c = NO_VERTEX);
|
||||
|
||||
// Print the result
|
||||
for j := 0 to NR_VERTICES - 1 do begin
|
||||
if (v[j].Distance = INFINITY) then begin
|
||||
// The algorithm never found a path to v[j]
|
||||
lineOut := SysUtils.Format( '%2d: inaccessible', [j]);
|
||||
end
|
||||
else begin
|
||||
// Build up the path of vertices, working backwards from v[j]
|
||||
lineOut := SysUtils.Format( '%2d', [j]);
|
||||
p := v[j].Previous;
|
||||
while (p <> NO_VERTEX) do begin
|
||||
lineOut := SysUtils.Format( '%2d --> ', [p]) + lineOut;
|
||||
p := v[p].Previous;
|
||||
end;
|
||||
// Print the path of vertices, preceded by distance from vertex 0
|
||||
lineOut := SysUtils.Format( '%2d: distance = %3d, ', [j, v[j].Distance]) + lineOut;
|
||||
end;
|
||||
WriteLn( lineOut);
|
||||
end;
|
||||
end.
|
||||
93
Task/Dijkstras-algorithm/Emacs-Lisp/dijkstras-algorithm.l
Normal file
93
Task/Dijkstras-algorithm/Emacs-Lisp/dijkstras-algorithm.l
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
;; Path format: (start-point end-point previous-point distance)
|
||||
(setq path-list `(
|
||||
(a b ,nil 7)
|
||||
(a c ,nil 9)
|
||||
(a f ,nil 14)
|
||||
(b c ,nil 10)
|
||||
(b d ,nil 15)
|
||||
(c d ,nil 11)
|
||||
(c f ,nil 2)
|
||||
(d e ,nil 6)
|
||||
(e f ,nil 9)
|
||||
))
|
||||
|
||||
(defun calculate-shortest-path ()
|
||||
(let ((shortest-path '())
|
||||
(head-point (nth 0 (nth 0 path-list))))
|
||||
|
||||
(defun combine-new-path (path1 path2)
|
||||
(list (nth 0 path1) (nth 1 path2) (nth 0 path2)
|
||||
(+ (nth 3 path1) (nth 3 path2))) )
|
||||
|
||||
(defun find-shortest-path (start end)
|
||||
(seq-find (lambda (item)
|
||||
(and (eq (nth 0 item) start) (eq (nth 1 item) end)))
|
||||
shortest-path)
|
||||
)
|
||||
|
||||
(defun add-shortest-path (item)
|
||||
(add-to-list 'shortest-path item) )
|
||||
|
||||
|
||||
(defun process-path (path)
|
||||
|
||||
(if (eq head-point (nth 0 path))
|
||||
(add-to-list 'shortest-path path)
|
||||
(progn
|
||||
(dolist (spath shortest-path)
|
||||
(when (eq (nth 1 spath) (nth 0 path))
|
||||
(let* ((new-path (combine-new-path spath path))
|
||||
(spath-found (find-shortest-path (nth 0 new-path)
|
||||
(nth 1 new-path))))
|
||||
(if spath-found
|
||||
(when (< (nth 3 new-path) (nth 3 spath-found))
|
||||
(setcdr (nthcdr 1 spath-found) (list (nth 2 new-path) (nth 3 new-path)))
|
||||
)
|
||||
|
||||
(add-shortest-path new-path)) ) ) ) ) ) )
|
||||
|
||||
|
||||
(defun find-shortest-route (start end)
|
||||
(let ((point-list '())
|
||||
(end-point end)
|
||||
path-found)
|
||||
(add-to-list 'point-list end)
|
||||
(catch 'no-more-path
|
||||
(while 't
|
||||
(setq path-found (find-shortest-path start end-point))
|
||||
(if (or (not path-found) (not (nth 2 path-found)))
|
||||
(throw 'no-more-path nil)
|
||||
(progn
|
||||
(add-to-list 'point-list (nth 2 path-found))
|
||||
(setq end-point (nth 2 path-found)) )
|
||||
)
|
||||
)
|
||||
)
|
||||
(add-to-list 'point-list start)
|
||||
)
|
||||
)
|
||||
|
||||
(defun show-shortest-path (start end)
|
||||
(let ((path-found (find-shortest-path start end))
|
||||
(route-found (find-shortest-route start end)))
|
||||
(if path-found
|
||||
(progn
|
||||
(message "shortest distance: %s" (nth 3 path-found))
|
||||
(message "shortest route: %s" route-found) )
|
||||
(message "shortest path not found") )
|
||||
)
|
||||
(message "--") )
|
||||
|
||||
;; Process each path
|
||||
(dolist (path path-list)
|
||||
(process-path path) )
|
||||
|
||||
(message "from %s to %s:" 'a 'e)
|
||||
(show-shortest-path 'a 'e)
|
||||
(message "from %s to %s:" 'a 'f)
|
||||
(show-shortest-path 'a 'f)
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
(calculate-shortest-path)
|
||||
46
Task/Dijkstras-algorithm/Erlang/dijkstras-algorithm.erl
Normal file
46
Task/Dijkstras-algorithm/Erlang/dijkstras-algorithm.erl
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
-module(dijkstra).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-export([dijkstrafy/3]).
|
||||
|
||||
% just hide away recursion so we have a nice interface
|
||||
dijkstrafy(Graph, Start, End) when is_map(Graph) ->
|
||||
shortest_path(Graph, [{0, [Start]}], End, #{}).
|
||||
|
||||
shortest_path(_Graph, [], _End, _Visited) ->
|
||||
% if we're not going anywhere, it's time to start going back
|
||||
{0, []};
|
||||
shortest_path(_Graph, [{Cost, [End | _] = Path} | _ ], End, _Visited) ->
|
||||
% this is the base case, and finally returns the distance and the path
|
||||
{Cost, lists:reverse(Path)};
|
||||
shortest_path(Graph, [{Cost, [Node | _ ] = Path} | Routes], End, Visited) ->
|
||||
% this is the recursive case.
|
||||
% here we build a list of new "unvisited" routes, where the stucture is
|
||||
% a tuple of cost, then a list of paths taken to get to that cost from the "Start"
|
||||
NewRoutes = [{Cost + NewCost, [NewNode | Path]}
|
||||
|| {NewCost, NewNode} <- maps:get(Node, Graph),
|
||||
not maps:get(NewNode, Visited, false)],
|
||||
shortest_path(
|
||||
Graph,
|
||||
% add the routes we ripped off earlier onto the new routes
|
||||
% that we want to visit. sort the list of routes to get the
|
||||
% shortest routes (lowest cost) at the beginning.
|
||||
% Erlangs sort is already good enough, and it will sort the
|
||||
% tuples by the number at the beginning of each (the cost).
|
||||
lists:sort(NewRoutes ++ Routes),
|
||||
End,
|
||||
Visited#{Node => true}
|
||||
).
|
||||
|
||||
basic_test() ->
|
||||
Graph = #{
|
||||
a => [{7,b},{9,c},{14,f}],
|
||||
b => [{7,a},{10,c},{15,d}],
|
||||
c => [{10,b},{9,c},{11,d},{2,f}],
|
||||
d => [{15,b},{6,e},{11,c}],
|
||||
e => [{9,f},{6,d}],
|
||||
f => [{14,f},{2,c},{9,e}]
|
||||
},
|
||||
{Cost, Path} = dijkstrafy(Graph, a, e),
|
||||
{20,[a,c,f,e]} = {Cost, Path},
|
||||
io:format(user, "The total cost was ~p and the path was: ", [Cost]),
|
||||
io:format(user, "~w~n", [Path]).
|
||||
27
Task/Dijkstras-algorithm/F-Sharp/dijkstras-algorithm-1.fs
Normal file
27
Task/Dijkstras-algorithm/F-Sharp/dijkstras-algorithm-1.fs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//Dijkstra's algorithm: Nigel Galloway, August 5th., 2018
|
||||
[<CustomEquality;CustomComparison>]
|
||||
type Dijkstra<'N,'G when 'G:comparison>={toN:'N;cost:Option<'G>;fromN:'N}
|
||||
override g.Equals n =match n with| :? Dijkstra<'N,'G> as n->n.cost=g.cost|_->false
|
||||
override g.GetHashCode() = hash g.cost
|
||||
interface System.IComparable with
|
||||
member n.CompareTo g =
|
||||
match g with
|
||||
| :? Dijkstra<'N,'G> as n when n.cost=None -> (-1)
|
||||
| :? Dijkstra<'N,'G> when n.cost=None -> 1
|
||||
| :? Dijkstra<'N,'G> as g -> compare n.cost g.cost
|
||||
| _-> invalidArg "n" "expecting type Dijkstra<'N,'G>"
|
||||
let inline Dijkstra N G y =
|
||||
let rec fN l f=
|
||||
if List.isEmpty l then f
|
||||
else let n=List.min l
|
||||
if n.cost=None then f else
|
||||
fN(l|>List.choose(fun n'->if n'.toN=n.toN then None else match n.cost,n'.cost,Map.tryFind (n.toN,n'.toN) G with
|
||||
|Some g,None,Some wg ->Some {toN=n'.toN;cost=Some(g+wg);fromN=n.toN}
|
||||
|Some g,Some g',Some wg when g+wg<g'->Some {toN=n'.toN;cost=Some(g+wg);fromN=n.toN}
|
||||
|_ ->Some n'))((n.fromN,n.toN)::f)
|
||||
let r = fN (N|>List.map(fun n->{toN=n;cost=(Map.tryFind(y,n)G);fromN=y})) []
|
||||
(fun n->let rec fN z l=match List.tryFind(fun (_,g)->g=z) r with
|
||||
|Some(n',g') when y=n'->Some(n'::g'::l)
|
||||
|Some(n',g') ->fN n' (g'::l)
|
||||
|_ ->None
|
||||
fN n [])
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
type Node= |A|B|C|D|E|F
|
||||
let G=Map[((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)]
|
||||
let paths=Dijkstra [B;C;D;E;F] G A
|
||||
printfn "%A" (paths E)
|
||||
printfn "%A" (paths F)
|
||||
143
Task/Dijkstras-algorithm/Free-Pascal/dijkstras-algorithm.pas
Normal file
143
Task/Dijkstras-algorithm/Free-Pascal/dijkstras-algorithm.pas
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
program SsspDemo;
|
||||
{$mode delphi}
|
||||
uses
|
||||
SysUtils, Generics.Collections, PQueue;
|
||||
|
||||
type
|
||||
TArc = record
|
||||
Target: string;
|
||||
Cost: Integer;
|
||||
constructor Make(const t: string; c: Integer);
|
||||
end;
|
||||
TDigraph = class
|
||||
strict private
|
||||
FGraph: TObjectDictionary<string, TList<TArc>>;
|
||||
public
|
||||
const
|
||||
INF_WEIGHT = MaxInt;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure AddNode(const n: string);
|
||||
procedure AddArc(const s, t: string; c: Integer);
|
||||
function AdjacencyList(const n: string): TList<TArc>;
|
||||
function DijkstraSssp(const From: string; out PathTree: TDictionary<string, string>;
|
||||
out Dist: TDictionary<string, Integer>): Boolean;
|
||||
end;
|
||||
|
||||
constructor TArc.Make(const t: string; c: Integer);
|
||||
begin
|
||||
Target := t;
|
||||
Cost := c;
|
||||
end;
|
||||
|
||||
function CostCmp(const L, R: TArc): Boolean;
|
||||
begin
|
||||
Result := L.Cost > R.Cost;
|
||||
end;
|
||||
|
||||
constructor TDigraph.Create;
|
||||
begin
|
||||
FGraph := TObjectDictionary<string, TList<TArc>>.Create([doOwnsValues]);
|
||||
end;
|
||||
|
||||
destructor TDigraph.Destroy;
|
||||
begin
|
||||
FGraph.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TDigraph.AddNode(const n: string);
|
||||
begin
|
||||
if not FGraph.ContainsKey(n) then
|
||||
FGraph.Add(n, TList<TArc>.Create);
|
||||
end;
|
||||
|
||||
procedure TDigraph.AddArc(const s, t: string; c: Integer);
|
||||
begin
|
||||
AddNode(s);
|
||||
AddNode(t);
|
||||
if s <> t then
|
||||
FGraph.Items[s].Add(TArc.Make(t, c));
|
||||
end;
|
||||
|
||||
function TDigraph.AdjacencyList(const n: string): TList<TArc>;
|
||||
begin
|
||||
if not FGraph.TryGetValue(n, Result) then
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TDigraph.DijkstraSssp(const From: string; out PathTree: TDictionary<string, string>;
|
||||
out Dist: TDictionary<string, Integer>): Boolean;
|
||||
var
|
||||
q: TPriorityQueue<TArc>;
|
||||
Reached: THashSet<string>;
|
||||
Handles: TDictionary<string, q.THandle>;
|
||||
Next, Arc, Relax: TArc;
|
||||
h: q.THandle = -1;
|
||||
k: string;
|
||||
begin
|
||||
if not FGraph.ContainsKey(From) then exit(False);
|
||||
Reached := THashSet<string>.Create;
|
||||
Handles := TDictionary<string, q.THandle>.Create;
|
||||
Dist := TDictionary<string, Integer>.Create;
|
||||
for k in FGraph.Keys do
|
||||
Dist.Add(k, INF_WEIGHT);
|
||||
PathTree := TDictionary<string, string>.Create;
|
||||
q := TPriorityQueue<TArc>.Create(@CostCmp);
|
||||
PathTree.Add(From, '');
|
||||
Next := TArc.Make(From, 0);
|
||||
repeat
|
||||
Reached.Add(Next.Target);
|
||||
Dist[Next.Target] := Next.Cost;
|
||||
for Arc in AdjacencyList(Next.Target) do
|
||||
if not Reached.Contains(Arc.Target)then
|
||||
if Handles.TryGetValue(Arc.Target, h) then begin
|
||||
Relax := q.GetValue(h);
|
||||
if Arc.Cost + Next.Cost < Relax.Cost then begin
|
||||
q.Update(h, TArc.Make(Relax.Target, Arc.Cost + Next.Cost));
|
||||
PathTree[Arc.Target] := Next.Target;
|
||||
end
|
||||
end else begin
|
||||
Handles.Add(Arc.Target, q.Push(TArc.Make(Arc.Target, Arc.Cost + Next.Cost)));
|
||||
PathTree.Add(Arc.Target, Next.Target);
|
||||
end;
|
||||
until not q.TryPop(Next);
|
||||
Reached.Free;
|
||||
Handles.Free;
|
||||
q.Free;
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function ExtractPath(PathTree: TDictionary<string, string>; n: string): TStringArray;
|
||||
begin
|
||||
if not PathTree.ContainsKey(n) then exit(nil);
|
||||
with TList<string>.Create do begin
|
||||
repeat
|
||||
Add(n);
|
||||
n := PathTree[n];
|
||||
until n = '';
|
||||
Reverse;
|
||||
Result := ToArray;
|
||||
Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
const
|
||||
PathFmt = 'shortest path from "%s" to "%s": %s (cost = %d)';
|
||||
var
|
||||
g: TDigraph;
|
||||
Path: TDictionary<string, string>;
|
||||
Dist: TDictionary<string, Integer>;
|
||||
begin
|
||||
g := TDigraph.Create;
|
||||
g.AddArc('a', 'b', 7); g.AddArc('a', 'c', 9); g.AddArc('a', 'f', 14);
|
||||
g.AddArc('b', 'c', 10); g.AddArc('b', 'd', 15); g.AddArc('c', 'd', 11);
|
||||
g.AddArc('c', 'f', 2); g.AddArc('d', 'e', 6); g.AddArc('e', 'f', 9);
|
||||
g.DijkstraSssp('a', Path, Dist);
|
||||
WriteLn(Format(PathFmt, ['a', 'e', string.Join('->', ExtractPath(Path, 'e')), Dist['e']]));
|
||||
WriteLn(Format(PathFmt, ['a', 'f', string.Join('->', ExtractPath(Path, 'f')), Dist['f']]));
|
||||
g.Free;
|
||||
Path.Free;
|
||||
Dist.Free;
|
||||
readln;
|
||||
end.
|
||||
163
Task/Dijkstras-algorithm/Go/dijkstras-algorithm.go
Normal file
163
Task/Dijkstras-algorithm/Go/dijkstras-algorithm.go
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A PriorityQueue implements heap.Interface and holds Items.
|
||||
type PriorityQueue struct {
|
||||
items []Vertex
|
||||
m map[Vertex]int // value to index
|
||||
pr map[Vertex]int // value to priority
|
||||
}
|
||||
|
||||
func (pq *PriorityQueue) Len() int { return len(pq.items) }
|
||||
func (pq *PriorityQueue) Less(i, j int) bool { return pq.pr[pq.items[i]] < pq.pr[pq.items[j]] }
|
||||
func (pq *PriorityQueue) Swap(i, j int) {
|
||||
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
|
||||
pq.m[pq.items[i]] = i
|
||||
pq.m[pq.items[j]] = j
|
||||
}
|
||||
func (pq *PriorityQueue) Push(x interface{}) {
|
||||
n := len(pq.items)
|
||||
item := x.(Vertex)
|
||||
pq.m[item] = n
|
||||
pq.items = append(pq.items, item)
|
||||
}
|
||||
func (pq *PriorityQueue) Pop() interface{} {
|
||||
old := pq.items
|
||||
n := len(old)
|
||||
item := old[n-1]
|
||||
pq.m[item] = -1
|
||||
pq.items = old[0 : n-1]
|
||||
return item
|
||||
}
|
||||
|
||||
// update modifies the priority of an item in the queue.
|
||||
func (pq *PriorityQueue) update(item Vertex, priority int) {
|
||||
pq.pr[item] = priority
|
||||
heap.Fix(pq, pq.m[item])
|
||||
}
|
||||
func (pq *PriorityQueue) addWithPriority(item Vertex, priority int) {
|
||||
heap.Push(pq, item)
|
||||
pq.update(item, priority)
|
||||
}
|
||||
|
||||
const (
|
||||
Infinity = int(^uint(0) >> 1)
|
||||
Uninitialized = -1
|
||||
)
|
||||
|
||||
func Dijkstra(g Graph, source Vertex) (dist map[Vertex]int, prev map[Vertex]Vertex) {
|
||||
vs := g.Vertices()
|
||||
dist = make(map[Vertex]int, len(vs))
|
||||
prev = make(map[Vertex]Vertex, len(vs))
|
||||
sid := source
|
||||
dist[sid] = 0
|
||||
q := &PriorityQueue{
|
||||
items: make([]Vertex, 0, len(vs)),
|
||||
m: make(map[Vertex]int, len(vs)),
|
||||
pr: make(map[Vertex]int, len(vs)),
|
||||
}
|
||||
for _, v := range vs {
|
||||
if v != sid {
|
||||
dist[v] = Infinity
|
||||
}
|
||||
prev[v] = Uninitialized
|
||||
q.addWithPriority(v, dist[v])
|
||||
}
|
||||
for len(q.items) != 0 {
|
||||
u := heap.Pop(q).(Vertex)
|
||||
for _, v := range g.Neighbors(u) {
|
||||
alt := dist[u] + g.Weight(u, v)
|
||||
if alt < dist[v] {
|
||||
dist[v] = alt
|
||||
prev[v] = u
|
||||
q.update(v, alt)
|
||||
}
|
||||
}
|
||||
}
|
||||
return dist, prev
|
||||
}
|
||||
|
||||
// A Graph is the interface implemented by graphs that
|
||||
// this algorithm can run on.
|
||||
type Graph interface {
|
||||
Vertices() []Vertex
|
||||
Neighbors(v Vertex) []Vertex
|
||||
Weight(u, v Vertex) int
|
||||
}
|
||||
|
||||
// Nonnegative integer ID of vertex
|
||||
type Vertex int
|
||||
|
||||
// sg is a graph of strings that satisfies the Graph interface.
|
||||
type sg struct {
|
||||
ids map[string]Vertex
|
||||
names map[Vertex]string
|
||||
edges map[Vertex]map[Vertex]int
|
||||
}
|
||||
|
||||
func newsg(ids map[string]Vertex) sg {
|
||||
g := sg{ids: ids}
|
||||
g.names = make(map[Vertex]string, len(ids))
|
||||
for k, v := range ids {
|
||||
g.names[v] = k
|
||||
}
|
||||
g.edges = make(map[Vertex]map[Vertex]int)
|
||||
return g
|
||||
}
|
||||
func (g sg) edge(u, v string, w int) {
|
||||
if _, ok := g.edges[g.ids[u]]; !ok {
|
||||
g.edges[g.ids[u]] = make(map[Vertex]int)
|
||||
}
|
||||
g.edges[g.ids[u]][g.ids[v]] = w
|
||||
}
|
||||
func (g sg) path(v Vertex, prev map[Vertex]Vertex) (s string) {
|
||||
s = g.names[v]
|
||||
for prev[v] >= 0 {
|
||||
v = prev[v]
|
||||
s = g.names[v] + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
func (g sg) Vertices() []Vertex {
|
||||
vs := make([]Vertex, 0, len(g.ids))
|
||||
for _, v := range g.ids {
|
||||
vs = append(vs, v)
|
||||
}
|
||||
return vs
|
||||
}
|
||||
func (g sg) Neighbors(u Vertex) []Vertex {
|
||||
vs := make([]Vertex, 0, len(g.edges[u]))
|
||||
for v := range g.edges[u] {
|
||||
vs = append(vs, v)
|
||||
}
|
||||
return vs
|
||||
}
|
||||
func (g sg) Weight(u, v Vertex) int { return g.edges[u][v] }
|
||||
|
||||
func main() {
|
||||
g := newsg(map[string]Vertex{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
"f": 6,
|
||||
})
|
||||
g.edge("a", "b", 7)
|
||||
g.edge("a", "c", 9)
|
||||
g.edge("a", "f", 14)
|
||||
g.edge("b", "c", 10)
|
||||
g.edge("b", "d", 15)
|
||||
g.edge("c", "d", 11)
|
||||
g.edge("c", "f", 2)
|
||||
g.edge("d", "e", 6)
|
||||
g.edge("e", "f", 9)
|
||||
|
||||
dist, prev := Dijkstra(g, g.ids["a"])
|
||||
fmt.Printf("Distance to %s: %d, Path: %s\n", "e", dist[g.ids["e"]], g.path(g.ids["e"], prev))
|
||||
fmt.Printf("Distance to %s: %d, Path: %s\n", "f", dist[g.ids["f"]], g.path(g.ids["f"], prev))
|
||||
}
|
||||
58
Task/Dijkstras-algorithm/Haskell/dijkstras-algorithm.hs
Normal file
58
Task/Dijkstras-algorithm/Haskell/dijkstras-algorithm.hs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{-# LANGUAGE FlexibleContexts #-}
|
||||
import Data.Array
|
||||
import Data.Array.MArray
|
||||
import Data.Array.ST
|
||||
import Control.Monad.ST
|
||||
import Control.Monad (foldM)
|
||||
import Data.Set as S
|
||||
|
||||
dijkstra :: (Ix v, Num w, Ord w, Bounded w) => v -> v -> Array v [(v,w)] -> (Array v w, Array v v)
|
||||
dijkstra src invalid_index adj_list = runST $ do
|
||||
min_distance <- newSTArray b maxBound
|
||||
writeArray min_distance src 0
|
||||
previous <- newSTArray b invalid_index
|
||||
let aux vertex_queue =
|
||||
case S.minView vertex_queue of
|
||||
Nothing -> return ()
|
||||
Just ((dist, u), vertex_queue') ->
|
||||
let edges = adj_list ! u
|
||||
f vertex_queue (v, weight) = do
|
||||
let dist_thru_u = dist + weight
|
||||
old_dist <- readArray min_distance v
|
||||
if dist_thru_u >= old_dist then
|
||||
return vertex_queue
|
||||
else do
|
||||
let vertex_queue' = S.delete (old_dist, v) vertex_queue
|
||||
writeArray min_distance v dist_thru_u
|
||||
writeArray previous v u
|
||||
return $ S.insert (dist_thru_u, v) vertex_queue'
|
||||
in
|
||||
foldM f vertex_queue' edges >>= aux -- note that aux is being called within its own definition (i.e. aux is recursive). The foldM only iterates on the neighbours of v, it does not execute the while loop itself in Dijkstra's
|
||||
aux (S.singleton (0, src))
|
||||
m <- freeze min_distance
|
||||
p <- freeze previous
|
||||
return (m, p)
|
||||
where b = bounds adj_list
|
||||
newSTArray :: Ix i => (i,i) -> e -> ST s (STArray s i e)
|
||||
newSTArray = newArray
|
||||
|
||||
shortest_path_to :: (Ix v) => v -> v -> Array v v -> [v]
|
||||
shortest_path_to target invalid_index previous =
|
||||
aux target [] where
|
||||
aux vertex acc | vertex == invalid_index = acc
|
||||
| otherwise = aux (previous ! vertex) (vertex : acc)
|
||||
|
||||
adj_list :: Array Char [(Char, Int)]
|
||||
adj_list = listArray ('a', 'f') [ [('b',7), ('c',9), ('f',14)],
|
||||
[('a',7), ('c',10), ('d',15)],
|
||||
[('a',9), ('b',10), ('d',11), ('f',2)],
|
||||
[('b',15), ('c',11), ('e',6)],
|
||||
[('d',6), ('f',9)],
|
||||
[('a',14), ('c',2), ('e',9)] ]
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let (min_distance, previous) = dijkstra 'a' ' ' adj_list
|
||||
putStrLn $ "Distance from a to e: " ++ show (min_distance ! 'e')
|
||||
let path = shortest_path_to 'e' ' ' previous
|
||||
putStrLn $ "Path: " ++ show path
|
||||
130
Task/Dijkstras-algorithm/Huginn/dijkstras-algorithm.huginn
Normal file
130
Task/Dijkstras-algorithm/Huginn/dijkstras-algorithm.huginn
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
import Algorithms as algo;
|
||||
import Mathematics as math;
|
||||
import Text as text;
|
||||
|
||||
class Edge {
|
||||
_to = none;
|
||||
_name = none;
|
||||
_cost = none;
|
||||
constructor( to_, name_, cost_ ) {
|
||||
_to = to_;
|
||||
_name = name_;
|
||||
_cost = real( cost_ );
|
||||
}
|
||||
to_string() {
|
||||
return ( "{}<{}>".format( _name, _cost ) );
|
||||
}
|
||||
}
|
||||
|
||||
class Path {
|
||||
_id = none;
|
||||
_from = none;
|
||||
_cost = none;
|
||||
_names = none;
|
||||
constructor( toName_, ids_, names_ ) {
|
||||
_id = ids_[toName_];
|
||||
_names = names_;
|
||||
_cost = math.INFINITY;
|
||||
}
|
||||
less( other_ ) {
|
||||
return ( _cost < other_._cost );
|
||||
}
|
||||
update( from_, cost_ ) {
|
||||
_from = from_;
|
||||
_cost = cost_;
|
||||
}
|
||||
to_string() {
|
||||
return ( "{} via {} at cost {}".format( _names[_id], _from != none ? _names[_from] : none, _cost ) );
|
||||
}
|
||||
}
|
||||
|
||||
class Graph {
|
||||
_neighbours = [];
|
||||
_ids = {};
|
||||
_names = [];
|
||||
add_node( name_ ) {
|
||||
if ( name_ ∉ _ids ) {
|
||||
_ids[name_] = size( _names );
|
||||
_names.push( name_ );
|
||||
}
|
||||
}
|
||||
add_edge( from_, to_, cost_ ) {
|
||||
assert( ( from_ ∈ _ids ) && ( to_ ∈ _ids ) );
|
||||
from = _ids[from_];
|
||||
to = _ids[to_];
|
||||
if ( from >= size( _neighbours ) ) {
|
||||
_neighbours.resize( from + 1, [] );
|
||||
}
|
||||
_neighbours[from].push( Edge( to, to_, cost_ ) );
|
||||
}
|
||||
shortest_paths( from_ ) {
|
||||
assert( from_ ∈ _ids );
|
||||
from = _ids[from_];
|
||||
paths = algo.materialize( algo.map( _names, @[_ids, _names]( name ) { Path( name, _ids, _names ); } ), list );
|
||||
paths[from].update( none, 0.0 );
|
||||
todo = algo.sorted( paths, @(x){-x._cost;} );
|
||||
while ( size( todo ) > 0 ) {
|
||||
node = todo[-1]._id;
|
||||
todo.resize( size( todo ) - 1, none );
|
||||
if ( node >= size( _neighbours ) ) {
|
||||
continue;
|
||||
}
|
||||
neighbours = _neighbours[node];
|
||||
for ( n : neighbours ) {
|
||||
newCost = n._cost + paths[node]._cost;
|
||||
if ( newCost < paths[n._to]._cost ) {
|
||||
paths[n._to].update( node, newCost );
|
||||
}
|
||||
}
|
||||
todo = algo.sorted( todo, @(x){-x._cost;} );
|
||||
}
|
||||
return ( paths );
|
||||
}
|
||||
path( paths_, to_ ) {
|
||||
assert( to_ ∈ _ids );
|
||||
to = _ids[to_];
|
||||
p = [to_];
|
||||
while ( paths_[to]._from != none ) {
|
||||
to = paths_[to]._from;
|
||||
p.push( _names[to] );
|
||||
}
|
||||
return ( algo.materialize( algo.reversed( p ), list ) );
|
||||
}
|
||||
to_string() {
|
||||
s = "";
|
||||
for ( i, n : algo.enumerate( _neighbours ) ) {
|
||||
s += "{} -> {}\n".format( _names[i], n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
g = Graph();
|
||||
confStr = input();
|
||||
if ( confStr == none ) {
|
||||
return ( 1 );
|
||||
}
|
||||
conf = algo.materialize( algo.map( text.split( confStr ), integer ), tuple );
|
||||
assert( size( conf ) == 2 );
|
||||
for ( _ : algo.range( conf[0] ) ) {
|
||||
line = input();
|
||||
if ( line == none ) {
|
||||
return ( 1 );
|
||||
}
|
||||
g.add_node( line.strip() );
|
||||
}
|
||||
for ( _ : algo.range( conf[1] ) ) {
|
||||
line = input();
|
||||
if ( line == none ) {
|
||||
return ( 1 );
|
||||
}
|
||||
g.add_edge( algo.materialize( text.split( line.strip() ), tuple )... );
|
||||
}
|
||||
print( string( g ) );
|
||||
paths = g.shortest_paths( "a" );
|
||||
for ( p : paths ) {
|
||||
print( "{}\n".format( p ) );
|
||||
}
|
||||
print( "{}\n".format( g.path( paths, "e" ) ) );
|
||||
print( "{}\n".format( g.path( paths, "f" ) ) );
|
||||
}
|
||||
109
Task/Dijkstras-algorithm/Icon/dijkstras-algorithm.icon
Normal file
109
Task/Dijkstras-algorithm/Icon/dijkstras-algorithm.icon
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
procedure main(A)
|
||||
graph := getGraph()
|
||||
repeat {
|
||||
writes("What is the start node? ")
|
||||
start := \graph.nodes[read()] | stop()
|
||||
writes("What is the finish node? ")
|
||||
finish := read() | stop()
|
||||
|
||||
QMouse(graph,start,finish)
|
||||
waitForCompletion() # block until all quantum mice have finished
|
||||
|
||||
showPath(getBestMouse(),start.name,finish)
|
||||
cleanGraph(graph)
|
||||
}
|
||||
end
|
||||
|
||||
procedure getGraph()
|
||||
graph := Graph(table(),table())
|
||||
write("Enter edges as 'n1,n2,weight' (blank line terminates)")
|
||||
repeat {
|
||||
if *(line := trim(read())) = 0 then break
|
||||
line ? {
|
||||
n1 := 1(tab(upto(',')),move(1))
|
||||
n2 := 1(tab(upto(',')),move(1))
|
||||
w := tab(0)
|
||||
/graph.nodes[n1] := Node(n1,set())
|
||||
/graph.nodes[n2] := Node(n2,set())
|
||||
insert(graph.nodes[n1].targets,graph.nodes[n2])
|
||||
graph.weights[n1||":"||n2] := w
|
||||
}
|
||||
}
|
||||
return graph
|
||||
end
|
||||
|
||||
procedure showPath(mouse,start,finish)
|
||||
if \mouse then {
|
||||
path := mouse.getPath()
|
||||
writes("Weight: ",path.weight," -> ")
|
||||
every writes(" ",!path.nodes)
|
||||
write("\n")
|
||||
}
|
||||
else write("No path from ",start," to ",finish,"\n")
|
||||
end
|
||||
|
||||
# A "Quantum-mouse" for traversing graphs. Each mouse lives for just
|
||||
# one node but can spawn additional mice to search adjoining nodes.
|
||||
|
||||
global qMice, goodMice, region, qMiceEmpty
|
||||
|
||||
record Graph(nodes,weights)
|
||||
record Node(name,targets,weight)
|
||||
record Path(weight, nodes)
|
||||
|
||||
class QMouse(graph, loc, finish, path)
|
||||
|
||||
method getPath(); return path; end
|
||||
method atEnd(); return (finish == loc.name); end
|
||||
|
||||
method visit(n) # Visit if we don't already have a cheaper route to n
|
||||
newWeight := path.weight + graph.weights[loc.name||":"||n.name]
|
||||
critical region[n]: if /n.weight | (newWeight < n.weight) then {
|
||||
n.weight := newWeight
|
||||
unlock(region[n])
|
||||
return n
|
||||
}
|
||||
end
|
||||
|
||||
initially (g, l, f, p)
|
||||
initial { # Construct critical region mutexes and completion condvar
|
||||
qMiceEmpty := condvar()
|
||||
region := table()
|
||||
every region[n := !g.nodes] := mutex()
|
||||
qMice := mutex(set())
|
||||
cleanGraph(g)
|
||||
}
|
||||
graph := g
|
||||
loc := l
|
||||
finish := f
|
||||
/p := Path(0,[])
|
||||
path := Path(p.weight,copy(p.nodes))
|
||||
if *path.nodes > 0 then
|
||||
path.weight +:= g.weights[path.nodes[-1]||":"||loc.name]
|
||||
put(path.nodes, loc.name)
|
||||
insert(qMice,self)
|
||||
thread {
|
||||
if atEnd() then insert(goodMice, self) # This mouse found a finish
|
||||
every QMouse(g,visit(!loc.targets),f,path)
|
||||
delete(qMice, self) # Kill this mouse
|
||||
if *qMice=0 then signal(qMiceEmpty) # All mice are dead
|
||||
}
|
||||
end
|
||||
|
||||
procedure cleanGraph(graph)
|
||||
every (!graph.nodes).weight := &null
|
||||
goodMice := mutex(set())
|
||||
end
|
||||
|
||||
procedure getBestMouse()
|
||||
every mouse := !goodMice do { # Locate shortest path
|
||||
weight := mouse.getPath().weight
|
||||
/minPathWeight := weight
|
||||
if minPathWeight >=:= weight then bestMouse := mouse
|
||||
}
|
||||
return bestMouse
|
||||
end
|
||||
|
||||
procedure waitForCompletion()
|
||||
critical qMiceEmpty: while *qMice > 0 do wait(qMiceEmpty)
|
||||
end
|
||||
74
Task/Dijkstras-algorithm/J/dijkstras-algorithm-1.j
Normal file
74
Task/Dijkstras-algorithm/J/dijkstras-algorithm-1.j
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
NB. verbs and adverb
|
||||
parse_table=: ;:@:(LF&= [;._2 -.&CR)
|
||||
mp=: $:~ :(+/ .*) NB. matrix product
|
||||
min=: <./ NB. minimum
|
||||
Index=: (i.`)(`:6) NB. Index adverb
|
||||
|
||||
dijkstra=: dyad define
|
||||
'LINK WEIGHT'=. , (0 _ ,. 2) <;.3 y
|
||||
'SOURCE SINK'=. |: LINK
|
||||
FRONTIER=. , < {. x
|
||||
GOAL=. {: x
|
||||
enumerate=. 2&([\)&.>
|
||||
while. FRONTIER do.
|
||||
PATH_MASK=. FRONTIER (+./@:(-:"1/)&:>"0 _~ enumerate)~ LINK
|
||||
I=. PATH_MASK min Index@:mp WEIGHTS
|
||||
PATH=. I >@{ FRONTIER
|
||||
STATE=. {: PATH
|
||||
if. STATE -: GOAL do. PATH return. end.
|
||||
FRONTIER=. (<<< I) { FRONTIER NB. elision
|
||||
ADJACENCIES=. (STATE = SOURCE) # SINK
|
||||
FRONTIER=. FRONTIER , PATH <@,"1 0 ADJACENCIES
|
||||
end.
|
||||
EMPTY
|
||||
)
|
||||
|
||||
|
||||
|
||||
NB. The specific problem
|
||||
|
||||
INPUT=: noun define
|
||||
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
|
||||
)
|
||||
|
||||
T=: parse_table INPUT
|
||||
NAMED_LINKS=: _ 2 {. T
|
||||
NODES=: ~. , NAMED_LINKS NB. vector of boxed names
|
||||
NUMBERED_LINKS=: NODES i. NAMED_LINKS
|
||||
WEIGHTS=: _ ".&> _ _1 {. T
|
||||
GRAPH=: NUMBERED_LINKS ,. WEIGHTS NB. GRAPH is the numerical representation
|
||||
|
||||
|
||||
TERMINALS=: NODES (i. ;:) 'a e'
|
||||
|
||||
NODES {~ TERMINALS dijkstra GRAPH
|
||||
|
||||
Note 'Output'
|
||||
┌─┬─┬─┬─┐
|
||||
│a│c│d│e│
|
||||
└─┴─┴─┴─┘
|
||||
|
||||
TERMINALS and GRAPH are integer arrays:
|
||||
|
||||
TERMINALS
|
||||
0 5
|
||||
|
||||
GRAPH
|
||||
0 1 7
|
||||
0 2 9
|
||||
0 3 14
|
||||
1 2 10
|
||||
1 4 15
|
||||
2 4 11
|
||||
2 3 2
|
||||
4 5 6
|
||||
5 3 9
|
||||
)
|
||||
43
Task/Dijkstras-algorithm/J/dijkstras-algorithm-2.j
Normal file
43
Task/Dijkstras-algorithm/J/dijkstras-algorithm-2.j
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
vertices=: ;:'a b c d e f'
|
||||
edges=:|: ;:;._2]0 :0
|
||||
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
|
||||
)
|
||||
|
||||
shortest_path=:1 :0
|
||||
:
|
||||
NB. x: path endpoints, m: vertex labels, y: edges (starts,ends,:costs)
|
||||
terminals=. m i. x
|
||||
starts=. m i. 0{y
|
||||
ends=. m i. 1{y
|
||||
tolls=. _&".@> 2{y
|
||||
C=. tolls (starts,&.>ends)}_$~2##m
|
||||
bestprice=. (<terminals){ (<. <./ .+/~)^:_ C
|
||||
best=. i.0
|
||||
if. _>bestprice do.
|
||||
paths=. ,.{.terminals
|
||||
goal=. {:terminals
|
||||
costs=. ,0
|
||||
while. #costs do.
|
||||
next=. ({:paths){C
|
||||
keep=. (_>next)*bestprice>:next+costs
|
||||
rep=. +/"1 keep
|
||||
paths=. (rep#"1 paths),(#m)|I.,keep
|
||||
costs=. (rep#"1 costs)+keep #&, next
|
||||
if. #j=. I. goal = {:paths do.
|
||||
best=. best, (bestprice=j{costs)# <"1 j{|:paths
|
||||
end.
|
||||
toss=. <<<j,I.bestprice<:costs
|
||||
paths=. toss {"1 paths
|
||||
costs=. toss { costs
|
||||
end.
|
||||
end.
|
||||
best {L:0 _ m
|
||||
)
|
||||
6
Task/Dijkstras-algorithm/J/dijkstras-algorithm-3.j
Normal file
6
Task/Dijkstras-algorithm/J/dijkstras-algorithm-3.j
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
(;:'a e') vertices shortest_path edges
|
||||
┌─────────┐
|
||||
│┌─┬─┬─┬─┐│
|
||||
││a│c│d│e││
|
||||
│└─┴─┴─┴─┘│
|
||||
└─────────┘
|
||||
160
Task/Dijkstras-algorithm/Java/dijkstras-algorithm.java
Normal file
160
Task/Dijkstras-algorithm/Java/dijkstras-algorithm.java
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class Dijkstra {
|
||||
private static final Graph.Edge[] GRAPH = {
|
||||
new Graph.Edge("a", "b", 7),
|
||||
new Graph.Edge("a", "c", 9),
|
||||
new Graph.Edge("a", "f", 14),
|
||||
new Graph.Edge("b", "c", 10),
|
||||
new Graph.Edge("b", "d", 15),
|
||||
new Graph.Edge("c", "d", 11),
|
||||
new Graph.Edge("c", "f", 2),
|
||||
new Graph.Edge("d", "e", 6),
|
||||
new Graph.Edge("e", "f", 9),
|
||||
};
|
||||
private static final String START = "a";
|
||||
private static final String END = "e";
|
||||
|
||||
public static void main(String[] args) {
|
||||
Graph g = new Graph(GRAPH);
|
||||
g.dijkstra(START);
|
||||
g.printPath(END);
|
||||
//g.printAllPaths();
|
||||
}
|
||||
}
|
||||
|
||||
class Graph {
|
||||
private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges
|
||||
|
||||
/** One edge of the graph (only used by Graph constructor) */
|
||||
public static class Edge {
|
||||
public final String v1, v2;
|
||||
public final int dist;
|
||||
public Edge(String v1, String v2, int dist) {
|
||||
this.v1 = v1;
|
||||
this.v2 = v2;
|
||||
this.dist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
/** One vertex of the graph, complete with mappings to neighbouring vertices */
|
||||
public static class Vertex implements Comparable<Vertex>{
|
||||
public final String name;
|
||||
public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
|
||||
public Vertex previous = null;
|
||||
public final Map<Vertex, Integer> neighbours = new HashMap<>();
|
||||
|
||||
public Vertex(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private void printPath()
|
||||
{
|
||||
if (this == this.previous)
|
||||
{
|
||||
System.out.printf("%s", this.name);
|
||||
}
|
||||
else if (this.previous == null)
|
||||
{
|
||||
System.out.printf("%s(unreached)", this.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.previous.printPath();
|
||||
System.out.printf(" -> %s(%d)", this.name, this.dist);
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(Vertex other)
|
||||
{
|
||||
if (dist == other.dist)
|
||||
return name.compareTo(other.name);
|
||||
|
||||
return Integer.compare(dist, other.dist);
|
||||
}
|
||||
|
||||
@Override public String toString()
|
||||
{
|
||||
return "(" + name + ", " + dist + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds a graph from a set of edges */
|
||||
public Graph(Edge[] edges) {
|
||||
graph = new HashMap<>(edges.length);
|
||||
|
||||
//one pass to find all vertices
|
||||
for (Edge e : edges) {
|
||||
if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1));
|
||||
if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2));
|
||||
}
|
||||
|
||||
//another pass to set neighbouring vertices
|
||||
for (Edge e : edges) {
|
||||
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
|
||||
//graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
|
||||
}
|
||||
}
|
||||
|
||||
/** Runs dijkstra using a specified source vertex */
|
||||
public void dijkstra(String startName) {
|
||||
if (!graph.containsKey(startName)) {
|
||||
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
|
||||
return;
|
||||
}
|
||||
final Vertex source = graph.get(startName);
|
||||
NavigableSet<Vertex> q = new TreeSet<>();
|
||||
|
||||
// set-up vertices
|
||||
for (Vertex v : graph.values()) {
|
||||
v.previous = v == source ? source : null;
|
||||
v.dist = v == source ? 0 : Integer.MAX_VALUE;
|
||||
q.add(v);
|
||||
}
|
||||
|
||||
dijkstra(q);
|
||||
}
|
||||
|
||||
/** Implementation of dijkstra's algorithm using a binary heap. */
|
||||
private void dijkstra(final NavigableSet<Vertex> q) {
|
||||
Vertex u, v;
|
||||
while (!q.isEmpty()) {
|
||||
|
||||
u = q.pollFirst(); // vertex with shortest distance (first iteration will return source)
|
||||
if (u.dist == Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable
|
||||
|
||||
//look at distances to each neighbour
|
||||
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
|
||||
v = a.getKey(); //the neighbour in this iteration
|
||||
|
||||
final int alternateDist = u.dist + a.getValue();
|
||||
if (alternateDist < v.dist) { // shorter path to neighbour found
|
||||
q.remove(v);
|
||||
v.dist = alternateDist;
|
||||
v.previous = u;
|
||||
q.add(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints a path from the source to the specified vertex */
|
||||
public void printPath(String endName) {
|
||||
if (!graph.containsKey(endName)) {
|
||||
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
|
||||
return;
|
||||
}
|
||||
|
||||
graph.get(endName).printPath();
|
||||
System.out.println();
|
||||
}
|
||||
/** Prints the path from the source to every vertex (output order is not guaranteed) */
|
||||
public void printAllPaths() {
|
||||
for (Vertex v : graph.values()) {
|
||||
v.printPath();
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Task/Dijkstras-algorithm/JavaScript/dijkstras-algorithm.js
Normal file
85
Task/Dijkstras-algorithm/JavaScript/dijkstras-algorithm.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
const dijkstra = (edges,source,target) => {
|
||||
const Q = new Set(),
|
||||
prev = {},
|
||||
dist = {},
|
||||
adj = {}
|
||||
|
||||
const vertex_with_min_dist = (Q,dist) => {
|
||||
let min_distance = Infinity,
|
||||
u = null
|
||||
|
||||
for (let v of Q) {
|
||||
if (dist[v] < min_distance) {
|
||||
min_distance = dist[v]
|
||||
u = v
|
||||
}
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
for (let i=0;i<edges.length;i++) {
|
||||
let v1 = edges[i][0],
|
||||
v2 = edges[i][1],
|
||||
len = edges[i][2]
|
||||
|
||||
Q.add(v1)
|
||||
Q.add(v2)
|
||||
|
||||
dist[v1] = Infinity
|
||||
dist[v2] = Infinity
|
||||
|
||||
if (adj[v1] === undefined) adj[v1] = {}
|
||||
if (adj[v2] === undefined) adj[v2] = {}
|
||||
|
||||
adj[v1][v2] = len
|
||||
adj[v2][v1] = len
|
||||
}
|
||||
|
||||
dist[source] = 0
|
||||
|
||||
while (Q.size) {
|
||||
let u = vertex_with_min_dist(Q,dist),
|
||||
neighbors = Object.keys(adj[u]).filter(v=>Q.has(v)) //Neighbor still in Q
|
||||
|
||||
Q.delete(u)
|
||||
|
||||
if (u===target) break //Break when the target has been found
|
||||
|
||||
for (let v of neighbors) {
|
||||
let alt = dist[u] + adj[u][v]
|
||||
if (alt < dist[v]) {
|
||||
dist[v] = alt
|
||||
prev[v] = u
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let u = target,
|
||||
S = [u],
|
||||
len = 0
|
||||
|
||||
while (prev[u] !== undefined) {
|
||||
S.unshift(prev[u])
|
||||
len += adj[u][prev[u]]
|
||||
u = prev[u]
|
||||
}
|
||||
return [S,len]
|
||||
}
|
||||
}
|
||||
|
||||
//Testing algorithm
|
||||
let graph = []
|
||||
graph.push(["a", "b", 7])
|
||||
graph.push(["a", "c", 9])
|
||||
graph.push(["a", "f", 14])
|
||||
graph.push(["b", "c", 10])
|
||||
graph.push(["b", "d", 15])
|
||||
graph.push(["c", "d", 11])
|
||||
graph.push(["c", "f", 2])
|
||||
graph.push(["d", "e", 6])
|
||||
graph.push(["e", "f", 9])
|
||||
|
||||
let [path,length] = dijkstra(graph, "a", "e");
|
||||
console.log(path) //[ 'a', 'c', 'f', 'e' ]
|
||||
console.log(length) //20
|
||||
68
Task/Dijkstras-algorithm/Jq/dijkstras-algorithm-1.jq
Normal file
68
Task/Dijkstras-algorithm/Jq/dijkstras-algorithm-1.jq
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# (*) If using gojq, uncomment the following line:
|
||||
# def keys_unsorted: keys;
|
||||
|
||||
# remove the first occurrence of $x from the input array
|
||||
def rm($x):
|
||||
index($x) as $ix
|
||||
| if $ix then .[:$ix] + .[$ix+1:] else . end;
|
||||
|
||||
# Input: a Graph
|
||||
# Output: a (possibly empty) stream of the neighbors of $node
|
||||
# that are also in the array $ary
|
||||
def neighbors($node; $ary:
|
||||
.[$node]
|
||||
| select(.)
|
||||
| keys_unsorted[]
|
||||
| . as $n
|
||||
| select($ary | index($n));
|
||||
|
||||
# Input: a Graph
|
||||
def vertices:
|
||||
[keys_unsorted[], (.[] | keys_unsorted[])] | unique;
|
||||
|
||||
# Input: a Graph
|
||||
# Output: the final version of the scratchpad
|
||||
def dijkstra($startname):
|
||||
. as $graph
|
||||
| vertices as $Q
|
||||
# scratchpad: { node: { prev, dist} }
|
||||
| reduce $Q[] as $v ({};
|
||||
. + { ($v): {prev: null, dist: infinite}} )
|
||||
| .[$startname].dist = 0
|
||||
| { scratchpad: ., $Q }
|
||||
| until( .Q|length == 0;
|
||||
.scratchpad as $scratchpad
|
||||
| ( .Q | min_by($scratchpad[.].dist)) as $u
|
||||
| .Q |= rm($u)
|
||||
| .Q as $Q
|
||||
# for each neighbor v of u still in Q:
|
||||
| reduce ($graph|neighbors($u; $Q)) as $v (.;
|
||||
(.scratchpad[$u].dist + $graph[$u][$v]) as $alt
|
||||
| if $alt < .scratchpad[$v].dist
|
||||
then .scratchpad[$v].dist = $alt
|
||||
| .scratchpad[$v].prev = $u
|
||||
else . end ) )
|
||||
| .scratchpad ;
|
||||
|
||||
# Input: a Graph
|
||||
# Output: the scratchpad
|
||||
def Dijkstra($startname):
|
||||
if .[$startname] == null then "The graph does not contain start vertex \(startname)"
|
||||
else dijkstra($startname)
|
||||
end;
|
||||
|
||||
# Input: scratchpad, i.e. a dictionary with key:value pairs of the form:
|
||||
# node: {prev, dist}
|
||||
# Output: an array, being
|
||||
# [optimal path from $node to $n, optimal distance from $node to $n]
|
||||
def readout($node):
|
||||
. as $in
|
||||
| $node
|
||||
| [recurse($in[.].prev; .)]
|
||||
| [reverse, $in[$node].dist] ;
|
||||
|
||||
# Input: a graph
|
||||
# Output: [path, value]
|
||||
def Dijkstra($startname; $endname):
|
||||
Dijkstra($startname)
|
||||
| readout($endname) ;
|
||||
13
Task/Dijkstras-algorithm/Jq/dijkstras-algorithm-2.jq
Normal file
13
Task/Dijkstras-algorithm/Jq/dijkstras-algorithm-2.jq
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
def GRAPH: {
|
||||
"a": {"b": 7, "c": 9, "f": 14},
|
||||
"b": {"c": 10, "d": 15},
|
||||
"c": {"d": 11, "f": 2},
|
||||
"d": {"e": 6},
|
||||
"e": {"f": 9}
|
||||
};
|
||||
|
||||
# To produce the final version of the scratchpad:
|
||||
# GRAPH | Dijkstra("a")
|
||||
|
||||
"\nThe shortest paths from a to e and to f:",
|
||||
(GRAPH | Dijkstra("a"; "e", "f") | .[0])
|
||||
80
Task/Dijkstras-algorithm/Julia/dijkstras-algorithm.julia
Normal file
80
Task/Dijkstras-algorithm/Julia/dijkstras-algorithm.julia
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
using Printf
|
||||
|
||||
struct Digraph{T <: Real,U}
|
||||
edges::Dict{Tuple{U,U},T}
|
||||
verts::Set{U}
|
||||
end
|
||||
|
||||
function Digraph(edges::Vector{Tuple{U,U,T}}) where {T <: Real,U}
|
||||
vnames = Set{U}(v for edge in edges for v in edge[1:2])
|
||||
adjmat = Dict((edge[1], edge[2]) => edge[3] for edge in edges)
|
||||
return Digraph(adjmat, vnames)
|
||||
end
|
||||
|
||||
vertices(g::Digraph) = g.verts
|
||||
edges(g::Digraph) = g.edges
|
||||
|
||||
neighbours(g::Digraph, v) = Set((b, c) for ((a, b), c) in edges(g) if a == v)
|
||||
|
||||
function dijkstrapath(g::Digraph{T,U}, source::U, dest::U) where {T, U}
|
||||
@assert source ∈ vertices(g) "$source is not a vertex in the graph"
|
||||
|
||||
# Easy case
|
||||
if source == dest return [source], 0 end
|
||||
# Initialize variables
|
||||
inf = typemax(T)
|
||||
dist = Dict(v => inf for v in vertices(g))
|
||||
prev = Dict(v => v for v in vertices(g))
|
||||
dist[source] = 0
|
||||
Q = copy(vertices(g))
|
||||
neigh = Dict(v => neighbours(g, v) for v in vertices(g))
|
||||
|
||||
# Main loop
|
||||
while !isempty(Q)
|
||||
u = reduce((x, y) -> dist[x] < dist[y] ? x : y, Q)
|
||||
pop!(Q, u)
|
||||
if dist[u] == inf || u == dest break end
|
||||
for (v, cost) in neigh[u]
|
||||
alt = dist[u] + cost
|
||||
if alt < dist[v]
|
||||
dist[v] = alt
|
||||
prev[v] = u
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Return path
|
||||
rst, cost = U[], dist[dest]
|
||||
if prev[dest] == dest
|
||||
return rst, cost
|
||||
else
|
||||
while dest != source
|
||||
pushfirst!(rst, dest)
|
||||
dest = prev[dest]
|
||||
end
|
||||
pushfirst!(rst, dest)
|
||||
return rst, cost
|
||||
end
|
||||
end
|
||||
|
||||
# testgraph = [("a", "b", 1), ("b", "e", 2), ("a", "e", 4)]
|
||||
const testgraph = [("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)]
|
||||
|
||||
function testpaths()
|
||||
g = Digraph(testgraph)
|
||||
src, dst = "a", "e"
|
||||
path, cost = dijkstrapath(g, src, dst)
|
||||
println("Shortest path from $src to $dst: ", isempty(path) ?
|
||||
"no possible path" : join(path, " → "), " (cost $cost)")
|
||||
# Print all possible paths
|
||||
@printf("\n%4s | %3s | %s\n", "src", "dst", "path")
|
||||
@printf("----------------\n")
|
||||
for src in vertices(g), dst in vertices(g)
|
||||
path, cost = dijkstrapath(g, src, dst)
|
||||
@printf("%4s | %3s | %s\n", src, dst, isempty(path) ? "no possible path" : join(path, " → ") * " ($cost)")
|
||||
end
|
||||
end
|
||||
|
||||
testpaths()
|
||||
147
Task/Dijkstras-algorithm/Kotlin/dijkstras-algorithm.kotlin
Normal file
147
Task/Dijkstras-algorithm/Kotlin/dijkstras-algorithm.kotlin
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// version 1.1.51
|
||||
|
||||
import java.util.TreeSet
|
||||
|
||||
class Edge(val v1: String, val v2: String, val dist: Int)
|
||||
|
||||
/** One vertex of the graph, complete with mappings to neighbouring vertices */
|
||||
class Vertex(val name: String) : Comparable<Vertex> {
|
||||
|
||||
var dist = Int.MAX_VALUE // MAX_VALUE assumed to be infinity
|
||||
var previous: Vertex? = null
|
||||
val neighbours = HashMap<Vertex, Int>()
|
||||
|
||||
fun printPath() {
|
||||
if (this == previous) {
|
||||
print(name)
|
||||
}
|
||||
else if (previous == null) {
|
||||
print("$name(unreached)")
|
||||
}
|
||||
else {
|
||||
previous!!.printPath()
|
||||
print(" -> $name($dist)")
|
||||
}
|
||||
}
|
||||
|
||||
override fun compareTo(other: Vertex): Int {
|
||||
if (dist == other.dist) return name.compareTo(other.name)
|
||||
return dist.compareTo(other.dist)
|
||||
}
|
||||
|
||||
override fun toString() = "($name, $dist)"
|
||||
}
|
||||
|
||||
class Graph(
|
||||
val edges: List<Edge>,
|
||||
val directed: Boolean,
|
||||
val showAllPaths: Boolean = false
|
||||
) {
|
||||
// mapping of vertex names to Vertex objects, built from a set of Edges
|
||||
private val graph = HashMap<String, Vertex>(edges.size)
|
||||
|
||||
init {
|
||||
// one pass to find all vertices
|
||||
for (e in edges) {
|
||||
if (!graph.containsKey(e.v1)) graph.put(e.v1, Vertex(e.v1))
|
||||
if (!graph.containsKey(e.v2)) graph.put(e.v2, Vertex(e.v2))
|
||||
}
|
||||
|
||||
// another pass to set neighbouring vertices
|
||||
for (e in edges) {
|
||||
graph[e.v1]!!.neighbours.put(graph[e.v2]!!, e.dist)
|
||||
// also do this for an undirected graph if applicable
|
||||
if (!directed) graph[e.v2]!!.neighbours.put(graph[e.v1]!!, e.dist)
|
||||
}
|
||||
}
|
||||
|
||||
/** Runs dijkstra using a specified source vertex */
|
||||
fun dijkstra(startName: String) {
|
||||
if (!graph.containsKey(startName)) {
|
||||
println("Graph doesn't contain start vertex '$startName'")
|
||||
return
|
||||
}
|
||||
val source = graph[startName]
|
||||
val q = TreeSet<Vertex>()
|
||||
|
||||
// set-up vertices
|
||||
for (v in graph.values) {
|
||||
v.previous = if (v == source) source else null
|
||||
v.dist = if (v == source) 0 else Int.MAX_VALUE
|
||||
q.add(v)
|
||||
}
|
||||
|
||||
dijkstra(q)
|
||||
}
|
||||
|
||||
/** Implementation of dijkstra's algorithm using a binary heap */
|
||||
private fun dijkstra(q: TreeSet<Vertex>) {
|
||||
while (!q.isEmpty()) {
|
||||
// vertex with shortest distance (first iteration will return source)
|
||||
val u = q.pollFirst()
|
||||
// if distance is infinite we can ignore 'u' (and any other remaining vertices)
|
||||
// since they are unreachable
|
||||
if (u.dist == Int.MAX_VALUE) break
|
||||
|
||||
//look at distances to each neighbour
|
||||
for (a in u.neighbours) {
|
||||
val v = a.key // the neighbour in this iteration
|
||||
|
||||
val alternateDist = u.dist + a.value
|
||||
if (alternateDist < v.dist) { // shorter path to neighbour found
|
||||
q.remove(v)
|
||||
v.dist = alternateDist
|
||||
v.previous = u
|
||||
q.add(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Prints a path from the source to the specified vertex */
|
||||
fun printPath(endName: String) {
|
||||
if (!graph.containsKey(endName)) {
|
||||
println("Graph doesn't contain end vertex '$endName'")
|
||||
return
|
||||
}
|
||||
print(if (directed) "Directed : " else "Undirected : ")
|
||||
graph[endName]!!.printPath()
|
||||
println()
|
||||
if (showAllPaths) printAllPaths() else println()
|
||||
}
|
||||
|
||||
/** Prints the path from the source to every vertex (output order is not guaranteed) */
|
||||
private fun printAllPaths() {
|
||||
for (v in graph.values) {
|
||||
v.printPath()
|
||||
println()
|
||||
}
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
val GRAPH = listOf(
|
||||
Edge("a", "b", 7),
|
||||
Edge("a", "c", 9),
|
||||
Edge("a", "f", 14),
|
||||
Edge("b", "c", 10),
|
||||
Edge("b", "d", 15),
|
||||
Edge("c", "d", 11),
|
||||
Edge("c", "f", 2),
|
||||
Edge("d", "e", 6),
|
||||
Edge("e", "f", 9)
|
||||
)
|
||||
|
||||
const val START = "a"
|
||||
const val END = "e"
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
with (Graph(GRAPH, true)) { // directed
|
||||
dijkstra(START)
|
||||
printPath(END)
|
||||
}
|
||||
with (Graph(GRAPH, false)) { // undirected
|
||||
dijkstra(START)
|
||||
printPath(END)
|
||||
}
|
||||
}
|
||||
67
Task/Dijkstras-algorithm/Lua/dijkstras-algorithm.lua
Normal file
67
Task/Dijkstras-algorithm/Lua/dijkstras-algorithm.lua
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
-- Graph definition
|
||||
local edges = {
|
||||
a = {b = 7, c = 9, f = 14},
|
||||
b = {c = 10, d = 15},
|
||||
c = {d = 11, f = 2},
|
||||
d = {e = 6},
|
||||
e = {f = 9}
|
||||
}
|
||||
|
||||
-- Fill in paths in the opposite direction to the stated edges
|
||||
function complete (graph)
|
||||
for node, edges in pairs(graph) do
|
||||
for edge, distance in pairs(edges) do
|
||||
if not graph[edge] then graph[edge] = {} end
|
||||
graph[edge][node] = distance
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Create path string from table of previous nodes
|
||||
function follow (trail, destination)
|
||||
local path, nextStep = destination, trail[destination]
|
||||
while nextStep do
|
||||
path = nextStep .. " " .. path
|
||||
nextStep = trail[nextStep]
|
||||
end
|
||||
return path
|
||||
end
|
||||
|
||||
-- Find the shortest path between the current and destination nodes
|
||||
function dijkstra (graph, current, destination, directed)
|
||||
if not directed then complete(graph) end
|
||||
local unvisited, distanceTo, trail = {}, {}, {}
|
||||
local nearest, nextNode, tentative
|
||||
for node, edgeDists in pairs(graph) do
|
||||
if node == current then
|
||||
distanceTo[node] = 0
|
||||
trail[current] = false
|
||||
else
|
||||
distanceTo[node] = math.huge
|
||||
unvisited[node] = true
|
||||
end
|
||||
end
|
||||
repeat
|
||||
nearest = math.huge
|
||||
for neighbour, pathDist in pairs(graph[current]) do
|
||||
if unvisited[neighbour] then
|
||||
tentative = distanceTo[current] + pathDist
|
||||
if tentative < distanceTo[neighbour] then
|
||||
distanceTo[neighbour] = tentative
|
||||
trail[neighbour] = current
|
||||
end
|
||||
if tentative < nearest then
|
||||
nearest = tentative
|
||||
nextNode = neighbour
|
||||
end
|
||||
end
|
||||
end
|
||||
unvisited[current] = false
|
||||
current = nextNode
|
||||
until unvisited[destination] == false or nearest == math.huge
|
||||
return distanceTo[destination], follow(trail, destination)
|
||||
end
|
||||
|
||||
-- Main procedure
|
||||
print("Directed:", dijkstra(edges, "a", "e", true))
|
||||
print("Undirected:", dijkstra(edges, "a", "e", false))
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
Module Dijkstra`s_algorithm {
|
||||
const max_number=1.E+306
|
||||
GetArr=lambda (n, val)->{
|
||||
dim d(n)=val
|
||||
=d()
|
||||
}
|
||||
term=("",0)
|
||||
Edges=(("a", ("b",7),("c",9),("f",14)),("b",("c",10),("d",15)),("c",("d",11),("f",2)),("d",("e",6)),("e",("f", 9)),("f",term))
|
||||
Document Doc$="Graph:"+{
|
||||
}
|
||||
ShowGraph()
|
||||
Doc$="Paths"+{
|
||||
}
|
||||
Print "Paths"
|
||||
For from_here=0 to 5
|
||||
pa=GetArr(len(Edges), -1)
|
||||
d=GetArr(len(Edges), max_number)
|
||||
Inventory S=1,2,3,4,5,6
|
||||
return d, from_here:=0
|
||||
RemoveMin=Lambda S, d, max_number-> {
|
||||
ss=each(S)
|
||||
min=max_number
|
||||
p=0
|
||||
while ss
|
||||
val=d#val(eval(S,ss^)-1)
|
||||
if min>val then let min=val : p=ss^
|
||||
end while
|
||||
=s(p!) ' use p as index not key
|
||||
Delete S, eval(s,p)
|
||||
}
|
||||
Show_Distance_and_Path$=lambda$ d, pa, from_here, max_number (n) -> {
|
||||
ret1$=chr$(from_here+asc("a"))+" to "+chr$(n+asc("a"))
|
||||
if d#val(n) =max_number then =ret1$+ " No Path" :exit
|
||||
let ret$="", mm=n, m=n
|
||||
repeat
|
||||
n=m
|
||||
ret$+=chr$(asc("a")+n)
|
||||
m=pa#val(n)
|
||||
until from_here=n
|
||||
=ret1$+format$("{0::-4} {1}",d#val(mm),strrev$(ret$))
|
||||
}
|
||||
while len(s)>0
|
||||
u=RemoveMin()
|
||||
rem Print u, chr$(u-1+asc("a"))
|
||||
Relaxed()
|
||||
end while
|
||||
For i=0 to len(d)-1
|
||||
line$=Show_Distance_and_Path$(i)
|
||||
Print line$
|
||||
doc$=line$+{
|
||||
}
|
||||
next
|
||||
next
|
||||
Clipboard Doc$
|
||||
End
|
||||
Sub Relaxed()
|
||||
local vertex=Edges#val(u-1), i
|
||||
local e=Len(vertex)-1, edge=(,), val
|
||||
for i=1 to e
|
||||
edge=vertex#val(i)
|
||||
if edge#val$(0)<>"" then
|
||||
val=Asc(edge#val$(0))-Asc("a")
|
||||
if d#val(val)>edge#val(1)+d#val(u-1) then return d, val:=edge#val(1)+d#val(u-1) : Return Pa, val:=u-1
|
||||
end if
|
||||
next
|
||||
end sub
|
||||
Sub ShowGraph()
|
||||
Print "Graph"
|
||||
local i
|
||||
for i=1 to len(Edges)
|
||||
show_edges(i)
|
||||
next
|
||||
end sub
|
||||
Sub show_edges(n)
|
||||
n--
|
||||
local vertex=Edges#val(n), line$
|
||||
local e=each(vertex 2 to end), v2=(,)
|
||||
While e
|
||||
v2=array(e)
|
||||
line$=vertex#val$(0)+if$(v2#val$(0)<>""->"->"+v2#val$(0)+format$(" {0::-2}",v2#val(1)),"")
|
||||
Print line$
|
||||
Doc$=line$+{
|
||||
}
|
||||
end while
|
||||
end sub
|
||||
}
|
||||
Dijkstra`s_algorithm
|
||||
5
Task/Dijkstras-algorithm/Maple/dijkstras-algorithm.maple
Normal file
5
Task/Dijkstras-algorithm/Maple/dijkstras-algorithm.maple
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
restart:
|
||||
with(GraphTheory):
|
||||
G:=Digraph([a,b,c,d,e,f],{[[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]}):
|
||||
DijkstrasAlgorithm(G,a);
|
||||
# [[[a], 0], [[a, b], 7], [[a, c], 9], [[a, c, d], 20], [[a, c, d, e], 26], [[a, c, f], 11]]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
bd = Graph[{"a" \[DirectedEdge] "b", "a" \[DirectedEdge] "c",
|
||||
"b" \[DirectedEdge] "c", "b" \[DirectedEdge] "d",
|
||||
"c" \[DirectedEdge] "d", "d" \[DirectedEdge] "e",
|
||||
"a" \[DirectedEdge] "f", "c" \[DirectedEdge] "f",
|
||||
"e" \[DirectedEdge] "f"},
|
||||
EdgeWeight -> {7, 9, 10, 15, 11, 6, 14, 2, 9},
|
||||
VertexLabels -> "Name", VertexLabelStyle -> Directive[Black, 20],
|
||||
ImagePadding -> 20]
|
||||
|
||||
FindShortestPath[bd, "a", "e", Method -> "Dijkstra"]
|
||||
-> {"a", "c", "d", "e"}
|
||||
14
Task/Dijkstras-algorithm/Maxima/dijkstras-algorithm.maxima
Normal file
14
Task/Dijkstras-algorithm/Maxima/dijkstras-algorithm.maxima
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
load(graphs)$
|
||||
g: create_graph([[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, "e"], [6, "f"]],
|
||||
[[[1, 2], 7],
|
||||
[[1, 3], 9],
|
||||
[[1, 6], 14],
|
||||
[[2, 3], 10],
|
||||
[[2, 4], 15],
|
||||
[[3, 4], 11],
|
||||
[[3, 6], 2],
|
||||
[[4, 5], 6],
|
||||
[[5, 6], 9]], directed)$
|
||||
|
||||
shortest_weighted_path(1, 5, g);
|
||||
/* [26, [1, 3, 4, 5]] */
|
||||
79
Task/Dijkstras-algorithm/Nim/dijkstras-algorithm.nim
Normal file
79
Task/Dijkstras-algorithm/Nim/dijkstras-algorithm.nim
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Dijkstra algorithm.
|
||||
|
||||
from algorithm import reverse
|
||||
import sets
|
||||
import strformat
|
||||
import tables
|
||||
|
||||
type
|
||||
Edge = tuple[src, dst: string; cost: int]
|
||||
Graph = object
|
||||
vertices: HashSet[string]
|
||||
neighbours: Table[string, seq[tuple[dst: string, cost: float]]]
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
proc initGraph(edges: openArray[Edge]): Graph =
|
||||
## Initialize a graph from an edge list.
|
||||
## Use floats for costs in order to compare to Inf value.
|
||||
|
||||
for (src, dst, cost) in edges:
|
||||
result.vertices.incl(src)
|
||||
result.vertices.incl(dst)
|
||||
result.neighbours.mgetOrPut(src, @[]).add((dst, cost.toFloat))
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
proc dijkstraPath(graph: Graph; first, last: string): seq[string] =
|
||||
## Find the path from "first" to "last" which minimizes the cost.
|
||||
|
||||
var dist = initTable[string, float]()
|
||||
var previous = initTable[string, string]()
|
||||
var notSeen = graph.vertices
|
||||
for vertex in graph.vertices:
|
||||
dist[vertex] = Inf
|
||||
dist[first] = 0
|
||||
|
||||
while notSeen.card > 0:
|
||||
# Search vertex with minimal distance.
|
||||
var vertex1: string
|
||||
var mindist = Inf
|
||||
for vertex in notSeen:
|
||||
if dist[vertex] < mindist:
|
||||
vertex1 = vertex
|
||||
mindist = dist[vertex]
|
||||
if vertex1 == last:
|
||||
break
|
||||
notSeen.excl(vertex1)
|
||||
# Find shortest paths to neighbours.
|
||||
for (vertex2, cost) in graph.neighbours.getOrDefault(vertex1):
|
||||
if vertex2 in notSeen:
|
||||
let altdist = dist[vertex1] + cost
|
||||
if altdist < dist[vertex2]:
|
||||
# Found a shorter path to go to vertex2.
|
||||
dist[vertex2] = altdist
|
||||
previous[vertex2] = vertex1 # To go to vertex2, go through vertex1.
|
||||
|
||||
# Build the path.
|
||||
var vertex = last
|
||||
while vertex.len > 0:
|
||||
result.add(vertex)
|
||||
vertex = previous.getOrDefault(vertex)
|
||||
result.reverse()
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
proc printPath(path: seq[string]) =
|
||||
## Print a path.
|
||||
stdout.write(fmt"Shortest path from '{path[0]}' to '{path[^1]}': {path[0]}")
|
||||
for i in 1..path.high:
|
||||
stdout.write(fmt" → {path[i]}")
|
||||
stdout.write('\n')
|
||||
|
||||
#---------------------------------------------------------------------------------------------------
|
||||
|
||||
let graph = initGraph([("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)])
|
||||
printPath(graph.dijkstraPath("a", "e"))
|
||||
printPath(graph.dijkstraPath("a", "f"))
|
||||
87
Task/Dijkstras-algorithm/OCaml/dijkstras-algorithm-1.ocaml
Normal file
87
Task/Dijkstras-algorithm/OCaml/dijkstras-algorithm-1.ocaml
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
let list_vertices graph =
|
||||
List.fold_left (fun acc ((a, b), _) ->
|
||||
let acc = if List.mem b acc then acc else b::acc in
|
||||
let acc = if List.mem a acc then acc else a::acc in
|
||||
acc
|
||||
) [] graph
|
||||
|
||||
let neighbors v =
|
||||
List.fold_left (fun acc ((a, b), d) ->
|
||||
if a = v then (b, d)::acc else acc
|
||||
) []
|
||||
|
||||
let remove_from v lst =
|
||||
let rec aux acc = function [] -> failwith "remove_from"
|
||||
| x::xs -> if x = v then List.rev_append acc xs else aux (x::acc) xs
|
||||
in aux [] lst
|
||||
|
||||
let with_smallest_distance q dist =
|
||||
match q with
|
||||
| [] -> assert false
|
||||
| x::xs ->
|
||||
let rec aux distance v = function
|
||||
| x::xs ->
|
||||
let d = Hashtbl.find dist x in
|
||||
if d < distance
|
||||
then aux d x xs
|
||||
else aux distance v xs
|
||||
| [] -> (v, distance)
|
||||
in
|
||||
aux (Hashtbl.find dist x) x xs
|
||||
|
||||
let dijkstra max_val zero add graph source target =
|
||||
let vertices = list_vertices graph in
|
||||
let dist_between u v =
|
||||
try List.assoc (u, v) graph
|
||||
with _ -> zero
|
||||
in
|
||||
let dist = Hashtbl.create 1 in
|
||||
let previous = Hashtbl.create 1 in
|
||||
List.iter (fun v -> (* initializations *)
|
||||
Hashtbl.add dist v max_val (* unknown distance function from source to v *)
|
||||
) vertices;
|
||||
Hashtbl.replace dist source zero; (* distance from source to source *)
|
||||
let rec loop = function [] -> ()
|
||||
| q ->
|
||||
let u, dist_u =
|
||||
with_smallest_distance q dist in (* vertex in q with smallest distance in dist *)
|
||||
if dist_u = max_val then
|
||||
failwith "vertices inaccessible"; (* all remaining vertices are inaccessible from source *)
|
||||
if u = target then () else begin
|
||||
let q = remove_from u q in
|
||||
List.iter (fun (v, d) ->
|
||||
if List.mem v q then begin
|
||||
let alt = add dist_u (dist_between u v) in
|
||||
let dist_v = Hashtbl.find dist v in
|
||||
if alt < dist_v then begin (* relax (u,v,a) *)
|
||||
Hashtbl.replace dist v alt;
|
||||
Hashtbl.replace previous v u; (* previous node in optimal path from source *)
|
||||
end
|
||||
end
|
||||
) (neighbors u graph);
|
||||
loop q
|
||||
end
|
||||
in
|
||||
loop vertices;
|
||||
let s = ref [] in
|
||||
let u = ref target in
|
||||
while Hashtbl.mem previous !u do
|
||||
s := !u :: !s;
|
||||
u := Hashtbl.find previous !u
|
||||
done;
|
||||
(source :: !s)
|
||||
|
||||
let () =
|
||||
let 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; ]
|
||||
in
|
||||
let p = dijkstra max_int 0 (+) graph "a" "e" in
|
||||
print_endline (String.concat " -> " p)
|
||||
56
Task/Dijkstras-algorithm/OCaml/dijkstras-algorithm-2.ocaml
Normal file
56
Task/Dijkstras-algorithm/OCaml/dijkstras-algorithm-2.ocaml
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
type vertex = int
|
||||
type weight = float
|
||||
type neighbor = vertex * weight
|
||||
module VertexSet = Set.Make(struct type t = weight * vertex let compare = compare end)
|
||||
|
||||
let dijkstra (src:vertex) (adj_list:neighbor list array) : weight array * vertex array =
|
||||
let n = Array.length adj_list in
|
||||
let min_distance = Array.make n infinity in
|
||||
min_distance.(src) <- 0.;
|
||||
let previous = Array.make n (-1) in
|
||||
let rec aux vertex_queue =
|
||||
if not (VertexSet.is_empty vertex_queue) then
|
||||
let dist, u = VertexSet.min_elt vertex_queue in
|
||||
let vertex_queue' = VertexSet.remove (dist, u) vertex_queue in
|
||||
let edges = adj_list.(u) in
|
||||
let f vertex_queue (v, weight) =
|
||||
let dist_thru_u = dist +. weight in
|
||||
if dist_thru_u >= min_distance.(v) then
|
||||
vertex_queue
|
||||
else begin
|
||||
let vertex_queue' = VertexSet.remove (min_distance.(v), v) vertex_queue in
|
||||
min_distance.(v) <- dist_thru_u;
|
||||
previous.(v) <- u;
|
||||
VertexSet.add (min_distance.(v), v) vertex_queue'
|
||||
end
|
||||
in
|
||||
aux (List.fold_left f vertex_queue' edges)
|
||||
in
|
||||
aux (VertexSet.singleton (min_distance.(src), src));
|
||||
min_distance, previous
|
||||
|
||||
let shortest_path_to (target : vertex) (previous : vertex array) : vertex list =
|
||||
let rec aux target acc =
|
||||
if target = -1 then
|
||||
acc
|
||||
else
|
||||
aux previous.(target) (target :: acc)
|
||||
in
|
||||
aux target []
|
||||
|
||||
let adj_list =
|
||||
[| [(1, 7.); (2, 9.); (5, 14.)]; (* 0 = a *)
|
||||
[(0, 7.); (2, 10.); (3, 15.)]; (* 1 = b *)
|
||||
[(0, 9.); (1, 10.); (3, 11.); (5, 2.)]; (* 2 = c *)
|
||||
[(1, 15.); (2, 11.); (4, 6.)]; (* 3 = d *)
|
||||
[(3, 6.); (5, 9.)]; (* 4 = e *)
|
||||
[(0, 14.); (2, 2.); (4, 9.)] (* 5 = f *)
|
||||
|]
|
||||
|
||||
let () =
|
||||
let min_distance, previous = dijkstra 0 adj_list in
|
||||
Printf.printf "Distance from 0 to 4: %f\n" min_distance.(4);
|
||||
let path = shortest_path_to 4 previous in
|
||||
print_string "Path: ";
|
||||
List.iter (Printf.printf "%d, ") path;
|
||||
print_newline ()
|
||||
19
Task/Dijkstras-algorithm/PARI-GP/dijkstras-algorithm.parigp
Normal file
19
Task/Dijkstras-algorithm/PARI-GP/dijkstras-algorithm.parigp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
shortestPath(G, startAt=1)={
|
||||
my(n=#G[,1],dist=vector(n,i,9e99),prev=dist,Q=2^n-1);
|
||||
dist[startAt]=0;
|
||||
while(Q,
|
||||
my(t=vecmin(vecextract(dist,Q)),u);
|
||||
if(t==9e99, break);
|
||||
for(i=1,#v,if(dist[i]==t && bittest(Q,i-1), u=i; break));
|
||||
Q-=1<<(u-1);
|
||||
for(i=1,n,
|
||||
if(!G[u,i],next);
|
||||
my(alt=dist[u]+G[u,i]);
|
||||
if (alt < dist[i],
|
||||
dist[i]=alt;
|
||||
prev[i]=u;
|
||||
)
|
||||
)
|
||||
);
|
||||
dist
|
||||
};
|
||||
69
Task/Dijkstras-algorithm/PHP/dijkstras-algorithm.php
Normal file
69
Task/Dijkstras-algorithm/PHP/dijkstras-algorithm.php
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
function dijkstra($graph_array, $source, $target) {
|
||||
$vertices = array();
|
||||
$neighbours = array();
|
||||
foreach ($graph_array as $edge) {
|
||||
array_push($vertices, $edge[0], $edge[1]);
|
||||
$neighbours[$edge[0]][] = array("end" => $edge[1], "cost" => $edge[2]);
|
||||
$neighbours[$edge[1]][] = array("end" => $edge[0], "cost" => $edge[2]);
|
||||
}
|
||||
$vertices = array_unique($vertices);
|
||||
|
||||
foreach ($vertices as $vertex) {
|
||||
$dist[$vertex] = INF;
|
||||
$previous[$vertex] = NULL;
|
||||
}
|
||||
|
||||
$dist[$source] = 0;
|
||||
$Q = $vertices;
|
||||
while (count($Q) > 0) {
|
||||
|
||||
// TODO - Find faster way to get minimum
|
||||
$min = INF;
|
||||
foreach ($Q as $vertex){
|
||||
if ($dist[$vertex] < $min) {
|
||||
$min = $dist[$vertex];
|
||||
$u = $vertex;
|
||||
}
|
||||
}
|
||||
|
||||
$Q = array_diff($Q, array($u));
|
||||
if ($dist[$u] == INF or $u == $target) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($neighbours[$u])) {
|
||||
foreach ($neighbours[$u] as $arr) {
|
||||
$alt = $dist[$u] + $arr["cost"];
|
||||
if ($alt < $dist[$arr["end"]]) {
|
||||
$dist[$arr["end"]] = $alt;
|
||||
$previous[$arr["end"]] = $u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$path = array();
|
||||
$u = $target;
|
||||
while (isset($previous[$u])) {
|
||||
array_unshift($path, $u);
|
||||
$u = $previous[$u];
|
||||
}
|
||||
array_unshift($path, $u);
|
||||
return $path;
|
||||
}
|
||||
|
||||
$graph_array = array(
|
||||
array("a", "b", 7),
|
||||
array("a", "c", 9),
|
||||
array("a", "f", 14),
|
||||
array("b", "c", 10),
|
||||
array("b", "d", 15),
|
||||
array("c", "d", 11),
|
||||
array("c", "f", 2),
|
||||
array("d", "e", 6),
|
||||
array("e", "f", 9)
|
||||
);
|
||||
|
||||
$path = dijkstra($graph_array, "a", "e");
|
||||
|
||||
echo "path is: ".implode(", ", $path)."\n";
|
||||
162
Task/Dijkstras-algorithm/Pascal/dijkstras-algorithm-1.pas
Normal file
162
Task/Dijkstras-algorithm/Pascal/dijkstras-algorithm-1.pas
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
program dijkstra(output);
|
||||
|
||||
type
|
||||
{ We dynamically build the list of vertices from the edge list,
|
||||
just to avoid repeating ourselves in the graph input. Vertices are linked
|
||||
together via their `next` pointers to form a list of all vertices (sorted by
|
||||
name), while the `previous` pointer indicates the previous vertex along the
|
||||
shortest path to this one. }
|
||||
vertex = record
|
||||
name: char;
|
||||
visited: boolean;
|
||||
distance: integer;
|
||||
previous: ^vertex;
|
||||
next: ^vertex;
|
||||
end;
|
||||
|
||||
vptr = ^vertex;
|
||||
|
||||
{ The graph is specified as an array of these }
|
||||
edge_desc = record
|
||||
source: char;
|
||||
dest: char;
|
||||
weight: integer;
|
||||
end;
|
||||
|
||||
const
|
||||
{ the input graph }
|
||||
edges: array of edge_desc = (
|
||||
(source:'a'; dest:'b'; weight:7),
|
||||
(source:'a'; dest:'c'; weight:9),
|
||||
(source:'a'; dest:'f'; weight:14),
|
||||
(source:'b'; dest:'c'; weight:10),
|
||||
(source:'b'; dest:'d'; weight:15),
|
||||
(source:'c'; dest:'d'; weight:11),
|
||||
(source:'c'; dest:'f'; weight:2),
|
||||
(source:'d'; dest:'e'; weight:6),
|
||||
(source:'e'; dest:'f'; weight:9)
|
||||
);
|
||||
|
||||
{ find the shortest path to all nodes starting from this one }
|
||||
origin: char = 'a';
|
||||
|
||||
var
|
||||
head_vertex: vptr = nil;
|
||||
curr, next, closest: vptr;
|
||||
vtx: vptr;
|
||||
dist: integer;
|
||||
edge: edge_desc;
|
||||
done: boolean = false;
|
||||
|
||||
{ allocate a new vertex node with the given name and `next` pointer }
|
||||
function new_vertex(key: char; next: vptr): vptr;
|
||||
|
||||
var
|
||||
vtx: vptr;
|
||||
begin
|
||||
new(vtx);
|
||||
vtx^.name := key;
|
||||
vtx^.visited := false;
|
||||
vtx^.distance := maxint;
|
||||
vtx^.previous := nil;
|
||||
vtx^.next := next;
|
||||
new_vertex := vtx;
|
||||
end;
|
||||
|
||||
|
||||
{ look up a vertex by name; create it if needed }
|
||||
function find_or_make_vertex(key: char): vptr; var
|
||||
vtx, prev, found: vptr;
|
||||
done: boolean;
|
||||
|
||||
begin
|
||||
|
||||
found := nil;
|
||||
if head_vertex = nil then
|
||||
head_vertex := new_vertex(key, nil)
|
||||
else if head_vertex^.name > key then
|
||||
head_vertex := new_vertex(key, head_vertex);
|
||||
|
||||
if head_vertex^.name = key then
|
||||
found := head_vertex
|
||||
else begin
|
||||
prev := head_vertex;
|
||||
vtx := head_vertex^.next;
|
||||
done := false;
|
||||
while not done do
|
||||
if vtx = nil then
|
||||
done := true
|
||||
else if vtx^.name >= key then
|
||||
done := true
|
||||
else begin
|
||||
prev := vtx;
|
||||
vtx := vtx^.next
|
||||
end;
|
||||
if vtx <> nil then
|
||||
if vtx^.name = key then
|
||||
found := vtx;
|
||||
if found = nil then begin
|
||||
prev^.next := new_vertex(key, vtx);
|
||||
found := prev^.next;
|
||||
end
|
||||
end;
|
||||
find_or_make_vertex := found
|
||||
end;
|
||||
|
||||
{ display the path to a vertex indicated by its `previous` pointer chain }
|
||||
procedure write_path(vtx: vptr);
|
||||
begin
|
||||
if vtx <> nil then begin
|
||||
if vtx^.previous <> nil then begin
|
||||
write_path(vtx^.previous);
|
||||
write('→');
|
||||
end;
|
||||
write(vtx^.name);
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
curr := find_or_make_vertex(origin);
|
||||
curr^.distance := 0;
|
||||
curr^.previous := nil;
|
||||
while not done do begin
|
||||
for edge in edges do begin
|
||||
if edge.source = curr^.name then begin
|
||||
next := find_or_make_vertex(edge.dest);
|
||||
dist := curr^.distance + edge.weight;
|
||||
if dist < next^.distance then begin
|
||||
next^.distance := dist;
|
||||
next^.previous := curr;
|
||||
end
|
||||
end
|
||||
end;
|
||||
curr^.visited := true;
|
||||
closest := nil;
|
||||
vtx := head_vertex;
|
||||
while vtx <> nil do begin
|
||||
if not vtx^.visited then
|
||||
if closest = nil then
|
||||
closest := vtx
|
||||
else if vtx^.distance < closest^.distance then
|
||||
closest := vtx;
|
||||
vtx := vtx^.next;
|
||||
end;
|
||||
if closest = nil then
|
||||
done := true
|
||||
else if closest^.distance = maxint then
|
||||
done := true;
|
||||
curr := closest;
|
||||
end;
|
||||
writeln('Shortest path to each vertex from ', origin, ':');
|
||||
vtx := head_vertex;
|
||||
while vtx <> nil do begin
|
||||
write(vtx^.name, ':', vtx^.distance);
|
||||
if vtx^.distance > 0 then begin
|
||||
write(' (');
|
||||
write_path(vtx);
|
||||
write(')');
|
||||
end;
|
||||
writeln();
|
||||
vtx := vtx^.next;
|
||||
end
|
||||
end.
|
||||
107
Task/Dijkstras-algorithm/Pascal/dijkstras-algorithm-2.pas
Normal file
107
Task/Dijkstras-algorithm/Pascal/dijkstras-algorithm-2.pas
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
program Dijkstra_console;
|
||||
// Demo of Dijkstra's algorithm.
|
||||
// Free Pascal (Lazarus), console application.
|
||||
|
||||
uses SysUtils;
|
||||
type
|
||||
TNodeSet = (setA, setB, setC);
|
||||
TNode = record
|
||||
NodeSet : TNodeSet;
|
||||
PrevIndex : integer; // previous node in path leading to this node
|
||||
PathLength : integer; // total length of path to this node
|
||||
end;
|
||||
|
||||
const
|
||||
// Rosetta code task
|
||||
NR_NODES = 6;
|
||||
START_INDEX = 0;
|
||||
NODE_NAMES: array [0..NR_NODES - 1] of string = ('a','b','c','d','e','f');
|
||||
// LENGTHS[j,k] = length of branch j -> k, or -1 if no such branch exists.
|
||||
LENGTHS : array [0..NR_NODES - 1] of array [0..NR_NODES - 1] of integer
|
||||
= ((-1, 7, 9,-1,-1,14),
|
||||
(-1,-1,10,15,-1,-1),
|
||||
(-1,-1,-1,11,-1, 2),
|
||||
(-1,-1,-1,-1, 6,-1),
|
||||
(-1,-1,-1,-1,-1, 9),
|
||||
(-1,-1,-1,-1,-1,-1));
|
||||
|
||||
var
|
||||
nodes : array [0..NR_NODES - 1] of TNode;
|
||||
j, j_min, k : integer;
|
||||
lastToSetA, nrInSetA: integer;
|
||||
branchLength, trialLength, minLength : integer;
|
||||
lineOut : string;
|
||||
begin
|
||||
// Initialize nodes: all in set C
|
||||
for j := 0 to NR_NODES - 1 do begin
|
||||
nodes[j].NodeSet := setC;
|
||||
// No need to initialize PrevIndex and PathLength, as they are
|
||||
// not used until a value has been assigned by the algorithm.
|
||||
end;
|
||||
|
||||
// Begin by transferring the start node to set A
|
||||
nodes[START_INDEX].NodeSet := setA;
|
||||
nodes[START_INDEX].PathLength := 0;
|
||||
nrInSetA := 1;
|
||||
lastToSetA := START_INDEX;
|
||||
|
||||
// Transfer nodes to set A one at a time, until all have been transferred
|
||||
while (nrInSetA < NR_NODES) do begin
|
||||
|
||||
// Step 1: Work through branches leading from the node that was most recently
|
||||
// transferred to set A, and deal with end nodes in set B or set C.
|
||||
for j := 0 to NR_NODES - 1 do begin
|
||||
branchLength := LENGTHS[ lastToSetA, j];
|
||||
if (branchLength >= 0) then begin
|
||||
// If the end node is in set B, and the path to the end node via lastToSetA
|
||||
// is shorter than the existing path, then update the path.
|
||||
if (nodes[j].NodeSet = setB) then begin
|
||||
trialLength := nodes[lastToSetA].PathLength + branchLength;
|
||||
if (trialLength < nodes[j].PathLength) then begin
|
||||
nodes[j].PrevIndex := lastToSetA;
|
||||
nodes[j].PathLength := trialLength;
|
||||
end;
|
||||
end
|
||||
// If the end node is in set C, transfer it to set B.
|
||||
else if (nodes[j].NodeSet = setC) then begin
|
||||
nodes[j].NodeSet := setB;
|
||||
nodes[j].PrevIndex := lastToSetA;
|
||||
nodes[j].PathLength := nodes[lastToSetA].PathLength + branchLength;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Step 2: Find the node in set B with the smallest path length,
|
||||
// and transfer that node to set A.
|
||||
// (Note that set B cannot be empty at this point.)
|
||||
minLength := -1; // just to stop compiler warning "might not have been initialized"
|
||||
j_min := -1; // index of node with smallest path length; will become >= 0
|
||||
for j := 0 to NR_NODES - 1 do begin
|
||||
if (nodes[j].NodeSet = setB) then begin
|
||||
if (j_min < 0) or (nodes[j].PathLength < minLength) then begin
|
||||
j_min := j;
|
||||
minLength := nodes[j].PathLength;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
nodes[j_min].NodeSet := setA;
|
||||
inc( nrInSetA);
|
||||
lastToSetA := j_min;
|
||||
end;
|
||||
|
||||
// Write result to console
|
||||
WriteLn( SysUtils.Format( 'Shortest paths from node %s:', [NODE_NAMES[START_INDEX]]));
|
||||
for j := 0 to NR_NODES - 1 do begin
|
||||
if (j <> START_INDEX) then begin
|
||||
k := j;
|
||||
lineOut := NODE_NAMES[k];
|
||||
repeat
|
||||
k := nodes[k].PrevIndex;
|
||||
lineOut := NODE_NAMES[k] + ' -> ' + lineOut;
|
||||
until (k = START_INDEX);
|
||||
lineOut := SysUtils.Format( '%3s: length %3d, ',
|
||||
[NODE_NAMES[j], nodes[j].PathLength]) + lineOut;
|
||||
WriteLn( lineOut);
|
||||
end;
|
||||
end;
|
||||
end.
|
||||
63
Task/Dijkstras-algorithm/Perl/dijkstras-algorithm.pl
Normal file
63
Task/Dijkstras-algorithm/Perl/dijkstras-algorithm.pl
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
use constant True => 1;
|
||||
|
||||
sub add_edge {
|
||||
my ($g, $a, $b, $weight) = @_;
|
||||
$g->{$a} ||= {name => $a};
|
||||
$g->{$b} ||= {name => $b};
|
||||
push @{$g->{$a}{edges}}, {weight => $weight, vertex => $g->{$b}};
|
||||
}
|
||||
|
||||
sub push_priority {
|
||||
my ($a, $v) = @_;
|
||||
my $i = 0;
|
||||
my $j = $#{$a};
|
||||
while ($i <= $j) {
|
||||
my $k = int(($i + $j) / 2);
|
||||
if ($a->[$k]{dist} >= $v->{dist}) { $j = $k - 1 }
|
||||
else { $i = $k + 1 }
|
||||
}
|
||||
splice @$a, $i, 0, $v;
|
||||
}
|
||||
|
||||
sub dijkstra {
|
||||
my ($g, $a, $b) = @_;
|
||||
for my $v (values %$g) {
|
||||
$v->{dist} = 10e7; # arbitrary large value
|
||||
delete @$v{'prev', 'visited'}
|
||||
}
|
||||
$g->{$a}{dist} = 0;
|
||||
my $h = [];
|
||||
push_priority($h, $g->{$a});
|
||||
while () {
|
||||
my $v = shift @$h;
|
||||
last if !$v or $v->{name} eq $b;
|
||||
$v->{visited} = True;
|
||||
for my $e (@{$v->{edges}}) {
|
||||
my $u = $e->{vertex};
|
||||
if (!$u->{visited} && $v->{dist} + $e->{weight} <= $u->{dist}) {
|
||||
$u->{prev} = $v;
|
||||
$u->{dist} = $v->{dist} + $e->{weight};
|
||||
push_priority($h, $u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $g = {};
|
||||
add_edge($g, @$_) for
|
||||
(['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]);
|
||||
|
||||
dijkstra($g, 'a', 'e');
|
||||
|
||||
my $v = $g->{e};
|
||||
my @a;
|
||||
while ($v) {
|
||||
push @a, $v->{name};
|
||||
$v = $v->{prev};
|
||||
}
|
||||
my $path = join '', reverse @a;
|
||||
print "$g->{e}{dist} $path\n";
|
||||
87
Task/Dijkstras-algorithm/Phix/dijkstras-algorithm.phix
Normal file
87
Task/Dijkstras-algorithm/Phix/dijkstras-algorithm.phix
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #000080;font-style:italic;">--requires("1.0.2") -- (builtin E renamed as EULER)
|
||||
--enum A,B,C,D,E,F</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">A</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">B</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">C</span><span style="color: #0000FF;">=</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">D</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">E</span><span style="color: #0000FF;">=</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">F</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span> <span style="color: #000080;font-style:italic;">-- (or use this)</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">edges</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">A</span><span style="color: #0000FF;">,</span><span style="color: #000000;">B</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">A</span><span style="color: #0000FF;">,</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">A</span><span style="color: #0000FF;">,</span><span style="color: #000000;">F</span><span style="color: #0000FF;">,</span><span style="color: #000000;">14</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">B</span><span style="color: #0000FF;">,</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">B</span><span style="color: #0000FF;">,</span><span style="color: #000000;">D</span><span style="color: #0000FF;">,</span><span style="color: #000000;">15</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,</span><span style="color: #000000;">D</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,</span><span style="color: #000000;">F</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">D</span><span style="color: #0000FF;">,</span><span style="color: #000000;">E</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">E</span><span style="color: #0000FF;">,</span><span style="color: #000000;">F</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">}}</span>
|
||||
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">visited</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">cost</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">from</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">reset</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">visited</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">cost</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">from</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">backtrack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">finish</span><span style="color: #0000FF;">,</span><span style="color: #000000;">start</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">finish</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">start</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">finish</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">from</span><span style="color: #0000FF;">[</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">shortest_path</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">start</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">finish</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">estart</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">eend</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ecost</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ncost</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mincost</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">visited</span><span style="color: #0000FF;">[</span><span style="color: #000000;">start</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">estart</span><span style="color: #0000FF;">,</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ecost</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">edges</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">estart</span><span style="color: #0000FF;">=</span><span style="color: #000000;">start</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">ncost</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">start</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">ecost</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">visited</span><span style="color: #0000FF;">[</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">from</span><span style="color: #0000FF;">[</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">]></span><span style="color: #000000;">ncost</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ncost</span>
|
||||
<span style="color: #000000;">from</span><span style="color: #0000FF;">[</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">start</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">eend</span><span style="color: #0000FF;">]></span><span style="color: #000000;">ncost</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- sanity check</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #000000;">mincost</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">visited</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">visited</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">and</span> <span style="color: #000000;">from</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">mincost</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">mincost</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
|
||||
<span style="color: #000000;">mincost</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">start</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">visited</span><span style="color: #0000FF;">[</span><span style="color: #000000;">start</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">start</span><span style="color: #0000FF;">=</span><span style="color: #000000;">finish</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">cost</span><span style="color: #0000FF;">[</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">AFi</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- output helper</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #008000;">'A'</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">testset</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">start</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">finish</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ecost</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">len</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">epath</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">path</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">testset</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">start</span><span style="color: #0000FF;">,</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ecost</span><span style="color: #0000FF;">,</span><span style="color: #000000;">epath</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">testset</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">reset</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">len</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">shortest_path</span><span style="color: #0000FF;">(</span><span style="color: #000000;">start</span><span style="color: #0000FF;">,</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">path</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">len</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"no path found"</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">apply</span><span style="color: #0000FF;">(</span><span style="color: #000000;">backtrack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">,</span><span style="color: #000000;">start</span><span style="color: #0000FF;">),</span><span style="color: #000000;">AFi</span><span style="color: #0000FF;">),</span><span style="color: #008000;">""</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%c->%c: length %d:%s (expected %d:%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">AFi</span><span style="color: #0000FF;">(</span><span style="color: #000000;">start</span><span style="color: #0000FF;">),</span><span style="color: #000000;">AFi</span><span style="color: #0000FF;">(</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">),</span><span style="color: #000000;">len</span><span style="color: #0000FF;">,</span><span style="color: #000000;">path</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ecost</span><span style="color: #0000FF;">,</span><span style="color: #000000;">epath</span><span style="color: #0000FF;">})</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #000000;">test</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">A</span><span style="color: #0000FF;">,</span><span style="color: #000000;">E</span><span style="color: #0000FF;">,</span><span style="color: #000000;">26</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ACDE"</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">A</span><span style="color: #0000FF;">,</span><span style="color: #000000;">F</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ACF"</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">F</span><span style="color: #0000FF;">,</span><span style="color: #000000;">A</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"none"</span><span style="color: #0000FF;">}})</span>
|
||||
<!--
|
||||
18
Task/Dijkstras-algorithm/PicoLisp/dijkstras-algorithm-1.l
Normal file
18
Task/Dijkstras-algorithm/PicoLisp/dijkstras-algorithm-1.l
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
(de neighbor (X Y Cost)
|
||||
(push (prop X 'neighbors) (cons Y Cost))
|
||||
(push (prop Y 'neighbors) (cons X Cost)) )
|
||||
|
||||
(de dijkstra (Curr Dest)
|
||||
(let Cost 0
|
||||
(until (== Curr Dest)
|
||||
(let (Min T Next)
|
||||
(for N (; Curr neighbors)
|
||||
(with (car N)
|
||||
(let D (+ Cost (cdr N))
|
||||
(unless (and (: distance) (>= D @))
|
||||
(=: distance D) ) )
|
||||
(when (> Min (: distance))
|
||||
(setq Min (: distance) Next This) )
|
||||
(del (asoq Curr (: neighbors)) (:: neighbors)) ) )
|
||||
(setq Curr Next Cost Min) ) )
|
||||
Cost ) )
|
||||
11
Task/Dijkstras-algorithm/PicoLisp/dijkstras-algorithm-2.l
Normal file
11
Task/Dijkstras-algorithm/PicoLisp/dijkstras-algorithm-2.l
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
(neighbor 'a 'b 7)
|
||||
(neighbor 'a 'c 9)
|
||||
(neighbor 'a 'f 14)
|
||||
(neighbor 'b 'c 10)
|
||||
(neighbor 'b 'd 15)
|
||||
(neighbor 'c 'd 11)
|
||||
(neighbor 'c 'f 2)
|
||||
(neighbor 'd 'e 6)
|
||||
(neighbor 'e 'f 9)
|
||||
|
||||
(dijkstra 'a 'e)
|
||||
46
Task/Dijkstras-algorithm/Prolog/dijkstras-algorithm.pro
Normal file
46
Task/Dijkstras-algorithm/Prolog/dijkstras-algorithm.pro
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
%___________________________________________________________________________
|
||||
|
||||
:-dynamic
|
||||
rpath/2. % A reversed path
|
||||
|
||||
edge(a,b,7).
|
||||
edge(a,c,9).
|
||||
edge(b,c,10).
|
||||
edge(b,d,15).
|
||||
edge(c,d,11).
|
||||
edge(d,e,6).
|
||||
edge(a,f,14).
|
||||
edge(c,f,2).
|
||||
edge(e,f,9).
|
||||
|
||||
path(From,To,Dist) :- edge(To,From,Dist).
|
||||
path(From,To,Dist) :- edge(From,To,Dist).
|
||||
|
||||
shorterPath([H|Path], Dist) :- % path < stored path? replace it
|
||||
rpath([H|T], D), !, Dist < D, % match target node [H|_]
|
||||
retract(rpath([H|_],_)),
|
||||
writef('%w is closer than %w\n', [[H|Path], [H|T]]),
|
||||
assert(rpath([H|Path], Dist)).
|
||||
shorterPath(Path, Dist) :- % Otherwise store a new path
|
||||
writef('New path:%w\n', [Path]),
|
||||
assert(rpath(Path,Dist)).
|
||||
|
||||
traverse(From, Path, Dist) :- % traverse all reachable nodes
|
||||
path(From, T, D), % For each neighbor
|
||||
not(memberchk(T, Path)), % which is unvisited
|
||||
shorterPath([T,From|Path], Dist+D), % Update shortest path and distance
|
||||
traverse(T,[From|Path],Dist+D). % Then traverse the neighbor
|
||||
|
||||
traverse(From) :-
|
||||
retractall(rpath(_,_)), % Remove solutions
|
||||
traverse(From,[],0). % Traverse from origin
|
||||
traverse(_).
|
||||
|
||||
go(From, To) :-
|
||||
traverse(From), % Find all distances
|
||||
rpath([To|RPath], Dist)-> % If the target was reached
|
||||
reverse([To|RPath], Path), % Report the path and distance
|
||||
Distance is round(Dist),
|
||||
writef('Shortest path is %w with distance %w = %w\n',
|
||||
[Path, Dist, Distance]);
|
||||
writef('There is no route from %w to %w\n', [From, To]).
|
||||
50
Task/Dijkstras-algorithm/Python/dijkstras-algorithm.py
Normal file
50
Task/Dijkstras-algorithm/Python/dijkstras-algorithm.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
from collections import namedtuple, deque
|
||||
from pprint import pprint as pp
|
||||
|
||||
|
||||
inf = float('inf')
|
||||
Edge = namedtuple('Edge', ['start', 'end', 'cost'])
|
||||
|
||||
class Graph():
|
||||
def __init__(self, edges):
|
||||
self.edges = [Edge(*edge) for edge in edges]
|
||||
# print(dir(self.edges[0]))
|
||||
self.vertices = {e.start for e in self.edges} | {e.end for e in self.edges}
|
||||
|
||||
def dijkstra(self, source, dest):
|
||||
assert source in self.vertices
|
||||
dist = {vertex: inf for vertex in self.vertices}
|
||||
previous = {vertex: None for vertex in self.vertices}
|
||||
dist[source] = 0
|
||||
q = self.vertices.copy()
|
||||
neighbours = {vertex: set() for vertex in self.vertices}
|
||||
for start, end, cost in self.edges:
|
||||
neighbours[start].add((end, cost))
|
||||
neighbours[end].add((start, cost))
|
||||
|
||||
#pp(neighbours)
|
||||
|
||||
while q:
|
||||
# pp(q)
|
||||
u = min(q, key=lambda vertex: dist[vertex])
|
||||
q.remove(u)
|
||||
if dist[u] == inf or u == dest:
|
||||
break
|
||||
for v, cost in neighbours[u]:
|
||||
alt = dist[u] + cost
|
||||
if alt < dist[v]: # Relax (u,v,a)
|
||||
dist[v] = alt
|
||||
previous[v] = u
|
||||
#pp(previous)
|
||||
s, u = deque(), dest
|
||||
while previous[u]:
|
||||
s.appendleft(u)
|
||||
u = previous[u]
|
||||
s.appendleft(u)
|
||||
return s
|
||||
|
||||
|
||||
graph = 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)])
|
||||
pp(graph.dijkstra("a", "e"))
|
||||
56
Task/Dijkstras-algorithm/REXX/dijkstras-algorithm.rexx
Normal file
56
Task/Dijkstras-algorithm/REXX/dijkstras-algorithm.rexx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*REXX program determines the least costly path between two vertices given a list. */
|
||||
$.= copies(9, digits() ) /*edge cost: indicates doesn't exist. */
|
||||
xList= '!. @. $. beg fin bestP best$ xx yy' /*common EXPOSEd variables for subs. */
|
||||
@abc= 'abcdefghijklmnopqrstuvwxyz' /*list of all the possible vertices. */
|
||||
verts= 0; edges= 0 /*the number of vertices and also edges*/
|
||||
do #=1 for length(@abc); _= substr(@abc, #, 1)
|
||||
call value translate(_), #; @@.#= _
|
||||
end /*#*/
|
||||
call def$ a b 7 /*define an edge and its cost. */
|
||||
call def$ a c 9 /* " " " " " " */
|
||||
call def$ a f 14 /* " " " " " " */
|
||||
call def$ b c 10 /* " " " " " " */
|
||||
call def$ b d 15 /* " " " " " " */
|
||||
call def$ c d 11 /* " " " " " " */
|
||||
call def$ c f 2 /* " " " " " " */
|
||||
call def$ d e 6 /* " " " " " " */
|
||||
call def$ e f 9 /* " " " " " " */
|
||||
beg= a; fin= e /*the BEGin and FINish vertexes. */
|
||||
say; say 'number of edges = ' edges
|
||||
say 'number of vertices = ' verts " ["left(@abc, verts)"]"
|
||||
best$= $.; bestP=
|
||||
say; do jv=2 to verts; call paths verts, jv; end /*jv*/
|
||||
@costIs= right('cost =', 16)
|
||||
if bestP==$. then say 'no path found.'
|
||||
else say 'best path =' translate(bestP, @abc, 123456789) @costIs best$
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
apath: parse arg pathx 1 p1 2 p2 3; Lp= length(pathx); $= $.p1.p2
|
||||
if $>=best$ then return
|
||||
pv= p2; do ka=3 to Lp; _= substr(pathx, ka, 1)
|
||||
if $.pv._>=best$ then return
|
||||
$= $ + $.pv._; if $>=best$ then return; pv= _
|
||||
end /*ka*/
|
||||
best$= $; bestP= pathx
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
def$: parse arg xx yy $ .; if $.xx.yy<$ & $.yy.xx<$ | xx==yy then return
|
||||
edges= edges + 1; verts= verts + ($.xx\==0) + ($.yy\==0)
|
||||
$.xx= 0; $.yy= 0; $.xx.yy= $
|
||||
say left('', 40) "cost of " @@.xx '───►' @@.yy " is " $
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
paths: procedure expose (xList); parse arg xx, yy, @.
|
||||
do kp=1 for xx; _= kp; !.kp= _; end /*build a path list.*/
|
||||
call .path 1
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
.path: procedure expose (xList); parse arg ?, _
|
||||
if ?>yy then do; if @.1\==beg | @.yy\==fin then return
|
||||
do #=1 for yy; _= _ || @.#; end /*#*/; call apath _
|
||||
end
|
||||
else do qq=1 for xx /*build vertex paths recursively*/
|
||||
do kp=1 for ?-1; if @.kp==!.qq then iterate qq; end /*kp*/
|
||||
@.?= !.qq; call .path ?+1 /*recursive call for next path. */
|
||||
end /*qq*/
|
||||
return
|
||||
22
Task/Dijkstras-algorithm/Racket/dijkstras-algorithm-1.rkt
Normal file
22
Task/Dijkstras-algorithm/Racket/dijkstras-algorithm-1.rkt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#lang racket
|
||||
(require (planet jaymccarthy/dijkstra:1:2))
|
||||
|
||||
(define edges
|
||||
'([a . ((b 7)(c 9)(f 14))]
|
||||
[b . ((c 10)(d 15))]
|
||||
[c . ((d 11)(f 2))]
|
||||
[d . ((e 6))]
|
||||
[e . ((f 9))]))
|
||||
|
||||
(define (node-edges n)
|
||||
(cond [(assoc n edges) => rest] ['()]))
|
||||
(define edge-weight second)
|
||||
(define edge-end first)
|
||||
|
||||
(match/values (shortest-path node-edges edge-weight edge-end 'a (λ(n) (eq? n 'e)))
|
||||
[(dists prevs)
|
||||
(displayln (~a "Distances from a: " (for/list ([(n d) dists]) (list n d))))
|
||||
(displayln (~a "Shortest path: "
|
||||
(let loop ([path '(e)])
|
||||
(cond [(eq? (first path) 'a) path]
|
||||
[(loop (cons (hash-ref prevs (first path)) path))]))))])
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Distances from a: ((b 7) (d 20) (a 0) (c 9) (f 11) (e 26))
|
||||
Shortest path: (a c d e)
|
||||
80
Task/Dijkstras-algorithm/Raku/dijkstras-algorithm.raku
Normal file
80
Task/Dijkstras-algorithm/Raku/dijkstras-algorithm.raku
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
class Graph {
|
||||
has (%.edges, %.nodes);
|
||||
|
||||
method new(*@args){
|
||||
my (%edges, %nodes);
|
||||
for @args {
|
||||
%edges{.[0] ~ .[1]} = $_;
|
||||
%nodes{.[0]}.push( .[0] ~ .[1] );
|
||||
%nodes{.[1]}.push( .[0] ~ .[1] );
|
||||
}
|
||||
self.bless(edges => %edges, nodes => %nodes);
|
||||
}
|
||||
|
||||
method neighbours ($source) {
|
||||
my (%neighbours, $edges);
|
||||
$edges = self.nodes{$source};
|
||||
for @$edges -> $x {
|
||||
for self.edges{$x}[0..1] -> $y {
|
||||
if $y ne $source {
|
||||
%neighbours{$y} = self.edges{$x}
|
||||
}
|
||||
}
|
||||
}
|
||||
return %neighbours
|
||||
}
|
||||
|
||||
method dijkstra ($source, $dest) {
|
||||
my (%node_data, $v, $u);
|
||||
my @q = self.nodes.keys;
|
||||
|
||||
for self.nodes.keys {
|
||||
%node_data{$_}{'dist'} = Inf;
|
||||
%node_data{$_}{'prev'} = '';
|
||||
}
|
||||
%node_data{$source}{'dist'} = 0;
|
||||
|
||||
while @q {
|
||||
# %node_data.perl.say;
|
||||
my ($mindist, $idx) =
|
||||
@((map {[%node_data{@q[$_]}{'dist'},$_]},^@q).min(*[0]));
|
||||
$u = @q[$idx];
|
||||
|
||||
if $mindist eq Inf {
|
||||
return ()
|
||||
}
|
||||
elsif $u eq $dest {
|
||||
my @s;
|
||||
while %node_data{$u}{'prev'} {
|
||||
@s.unshift($u);
|
||||
$u = %node_data{$u}{'prev'}
|
||||
}
|
||||
@s.unshift($source);
|
||||
return @s;
|
||||
}
|
||||
else {
|
||||
@q.splice($idx,1);
|
||||
}
|
||||
|
||||
for self.neighbours($u).kv -> $v, $edge {
|
||||
my $alt = %node_data{$u}{'dist'} + $edge[2];
|
||||
if $alt < %node_data{$v}{'dist'} {
|
||||
%node_data{$v}{'dist'} = $alt;
|
||||
%node_data{$v}{'prev'} = $u
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $a = Graph.new([
|
||||
["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]
|
||||
]).dijkstra('a', 'e').say;
|
||||
77
Task/Dijkstras-algorithm/Ring/dijkstras-algorithm.ring
Normal file
77
Task/Dijkstras-algorithm/Ring/dijkstras-algorithm.ring
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Project : Dijkstra's algorithm
|
||||
|
||||
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]]
|
||||
|
||||
dbegin = "a"
|
||||
dend = "e"
|
||||
powlen = pow(2,len(graph)) - 1
|
||||
dgraph = list(powlen)
|
||||
dtemp = list(powlen)
|
||||
lenold = 10
|
||||
lennew = 0
|
||||
sumold = 30
|
||||
sumnew = 0
|
||||
|
||||
powerset(graph)
|
||||
|
||||
for n = 1 to len(dgraph)
|
||||
dtemp[n] = str2list(substr(dgraph[n], " ", nl))
|
||||
next
|
||||
|
||||
for n = 1 to len(dtemp)
|
||||
if len(dtemp[n]) > 3 and dtemp[n][1] = dbegin and dtemp[n][len(dtemp[n])-1] = dend
|
||||
flag = 1
|
||||
for m = 1 to len(dtemp[n])/3-1
|
||||
if dtemp[n][m*3-1] != dtemp[n][m*3+1]
|
||||
flag = 0
|
||||
ok
|
||||
next
|
||||
if flag = 1
|
||||
lennew = len(dtemp[n])
|
||||
if lennew <= lenold
|
||||
lenold = lennew
|
||||
sumnew = 0
|
||||
for m = 1 to len(dtemp[n])/3
|
||||
sumnew = sumnew + dtemp[n][m*3]
|
||||
next
|
||||
if sumnew < sumold
|
||||
sumold = sumnew
|
||||
gend = dtemp[n]
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
next
|
||||
str = ""
|
||||
see dbegin + " " + dend + " : "
|
||||
for m = 1 to len(gend)/3
|
||||
str = str + gend[(m-1)*3 + 1] + " " + gend[(m-1)*3 + 2] + " " + gend[(m-1)*3 + 3] + " -> "
|
||||
next
|
||||
str = left(str,len(str)-4)
|
||||
str = str + " cost : " + sumold + nl
|
||||
see str + nl
|
||||
|
||||
func powerset(list)
|
||||
s = "{"
|
||||
p = 0
|
||||
for i = 2 to (2 << len(list)) - 1 step 2
|
||||
s = ""
|
||||
for j = 1 to len(list)
|
||||
if i & (1 << j)
|
||||
s = s + list[j][1] + " " + list[j][2] + " " + list[j][3] + " "
|
||||
ok
|
||||
next
|
||||
if right(s,1) = " "
|
||||
s = left(s,len(s)-1)
|
||||
ok
|
||||
p = p + 1
|
||||
dgraph[p] = s
|
||||
next
|
||||
71
Task/Dijkstras-algorithm/Ruby/dijkstras-algorithm.rb
Normal file
71
Task/Dijkstras-algorithm/Ruby/dijkstras-algorithm.rb
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
class Graph
|
||||
Vertex = Struct.new(:name, :neighbours, :dist, :prev)
|
||||
|
||||
def initialize(graph)
|
||||
@vertices = Hash.new{|h,k| h[k]=Vertex.new(k,[],Float::INFINITY)}
|
||||
@edges = {}
|
||||
graph.each do |(v1, v2, dist)|
|
||||
@vertices[v1].neighbours << v2
|
||||
@vertices[v2].neighbours << v1
|
||||
@edges[[v1, v2]] = @edges[[v2, v1]] = dist
|
||||
end
|
||||
@dijkstra_source = nil
|
||||
end
|
||||
|
||||
def dijkstra(source)
|
||||
return if @dijkstra_source == source
|
||||
q = @vertices.values
|
||||
q.each do |v|
|
||||
v.dist = Float::INFINITY
|
||||
v.prev = nil
|
||||
end
|
||||
@vertices[source].dist = 0
|
||||
until q.empty?
|
||||
u = q.min_by {|vertex| vertex.dist}
|
||||
break if u.dist == Float::INFINITY
|
||||
q.delete(u)
|
||||
u.neighbours.each do |v|
|
||||
vv = @vertices[v]
|
||||
if q.include?(vv)
|
||||
alt = u.dist + @edges[[u.name, v]]
|
||||
if alt < vv.dist
|
||||
vv.dist = alt
|
||||
vv.prev = u.name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@dijkstra_source = source
|
||||
end
|
||||
|
||||
def shortest_path(source, target)
|
||||
dijkstra(source)
|
||||
path = []
|
||||
u = target
|
||||
while u
|
||||
path.unshift(u)
|
||||
u = @vertices[u].prev
|
||||
end
|
||||
return path, @vertices[target].dist
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#<%s vertices=%p edges=%p>" % [self.class.name, @vertices.values, @edges]
|
||||
end
|
||||
end
|
||||
|
||||
g = Graph.new([ [: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],
|
||||
])
|
||||
|
||||
start, stop = :a, :e
|
||||
path, dist = g.shortest_path(start, stop)
|
||||
puts "shortest path from #{start} to #{stop} has cost #{dist}:"
|
||||
puts path.join(" -> ")
|
||||
119
Task/Dijkstras-algorithm/Rust/dijkstras-algorithm.rust
Normal file
119
Task/Dijkstras-algorithm/Rust/dijkstras-algorithm.rust
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::usize;
|
||||
|
||||
|
||||
struct Grid<T> {
|
||||
nodes: Vec<Node<T>>,
|
||||
}
|
||||
|
||||
struct Node<T> {
|
||||
data: T,
|
||||
edges: Vec<(usize,usize)>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
struct State {
|
||||
node: usize,
|
||||
cost: usize,
|
||||
}
|
||||
|
||||
// Manually implement Ord so we get a min-heap instead of a max-heap
|
||||
impl Ord for State {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
other.cost.cmp(&self.cost)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for State {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
type WeightedEdge = (usize, usize, usize);
|
||||
|
||||
impl<T> Grid<T> {
|
||||
fn new() -> Self {
|
||||
Grid { nodes: Vec::new() }
|
||||
}
|
||||
|
||||
fn add_node(&mut self, data: T) -> usize {
|
||||
let node = Node {
|
||||
edges: Vec::new(),
|
||||
data: data,
|
||||
};
|
||||
self.nodes.push(node);
|
||||
self.nodes.len() - 1
|
||||
}
|
||||
|
||||
fn create_edges<'a, I>(&mut self, iterator: I) where I: IntoIterator<Item=&'a WeightedEdge> {
|
||||
for &(start,end,weight) in iterator.into_iter() {
|
||||
self.nodes[start].edges.push((end,weight));
|
||||
self.nodes[end].edges.push((start,weight));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn find_path(&self, start: usize, end: usize) -> Option<(Vec<usize>, usize)> {
|
||||
let mut dist = vec![(usize::MAX, None); self.nodes.len()];
|
||||
|
||||
let mut heap = BinaryHeap::new();
|
||||
dist[start] = (0, None);
|
||||
heap.push(State {
|
||||
node: start,
|
||||
cost: 0,
|
||||
});
|
||||
|
||||
while let Some(State { node, cost }) = heap.pop() {
|
||||
if node == end {
|
||||
let mut path = Vec::with_capacity(dist.len() / 2);
|
||||
let mut current_dist = dist[end];
|
||||
path.push(end);
|
||||
while let Some(prev) = current_dist.1 {
|
||||
path.push(prev);
|
||||
current_dist = dist[prev];
|
||||
}
|
||||
path.reverse();
|
||||
return Some((path, cost));
|
||||
}
|
||||
|
||||
if cost > dist[node].0 {
|
||||
continue;
|
||||
}
|
||||
for edge in &self.nodes[node].edges {
|
||||
let next = State {
|
||||
node: edge.0,
|
||||
cost: cost + edge.1,
|
||||
};
|
||||
if next.cost < dist[next.node].0 {
|
||||
dist[next.node] = (next.cost, Some(node));
|
||||
heap.push(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut grid = Grid::new();
|
||||
let (a,b,c,d,e,f) = (grid.add_node("a"), grid.add_node("b"),
|
||||
grid.add_node("c"), grid.add_node("d"),
|
||||
grid.add_node("e"), grid.add_node("f"));
|
||||
|
||||
grid.create_edges(&[
|
||||
(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) ,
|
||||
]);
|
||||
|
||||
let (path, cost) = grid.find_path(a,e).unwrap();
|
||||
|
||||
print!("{}", grid.nodes[path[0]].data);
|
||||
for i in path.iter().skip(1) {
|
||||
print!(" -> {}", grid.nodes[*i].data);
|
||||
}
|
||||
println!("\nCost: {}", cost);
|
||||
|
||||
}
|
||||
38
Task/Dijkstras-algorithm/SAS/dijkstras-algorithm.sas
Normal file
38
Task/Dijkstras-algorithm/SAS/dijkstras-algorithm.sas
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* create SAS data set */
|
||||
data Edges;
|
||||
input Start $ End $ Cost;
|
||||
datalines;
|
||||
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
|
||||
;
|
||||
|
||||
/* call OPTMODEL procedure in SAS/OR */
|
||||
proc optmodel;
|
||||
/* declare sets and parameters, and read input data */
|
||||
set <str,str> LINKS;
|
||||
num cost {LINKS};
|
||||
read data Edges into LINKS=[start end] cost;
|
||||
set NODES = union {<i,j> in LINKS} {i,j};
|
||||
set SOURCES = {'a'};
|
||||
set SINKS = {'e'};
|
||||
/* <source,sink,order,from,to> */
|
||||
set <str,str,num,str,str> PATHS;
|
||||
|
||||
/* call network solver */
|
||||
solve with network /
|
||||
shortpath=(source=SOURCES sink=SINKS) links=(weight=cost) out=(sppaths=PATHS);
|
||||
|
||||
/* write shortest path to SAS data set */
|
||||
create data path from [source sink order from to]=PATHS cost[from,to];
|
||||
quit;
|
||||
|
||||
/* print shortest path */
|
||||
proc print data=path;
|
||||
run;
|
||||
29
Task/Dijkstras-algorithm/Scala/dijkstras-algorithm-1.scala
Normal file
29
Task/Dijkstras-algorithm/Scala/dijkstras-algorithm-1.scala
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
object Dijkstra {
|
||||
|
||||
type Path[Key] = (Double, List[Key])
|
||||
|
||||
def Dijkstra[Key](lookup: Map[Key, List[(Double, Key)]], fringe: List[Path[Key]], dest: Key, visited: Set[Key]): Path[Key] = fringe match {
|
||||
case (dist, path) :: fringe_rest => path match {case key :: path_rest =>
|
||||
if (key == dest) (dist, path.reverse)
|
||||
else {
|
||||
val paths = lookup(key).flatMap {case (d, key) => if (!visited.contains(key)) List((dist + d, key :: path)) else Nil}
|
||||
val sorted_fringe = (paths ++ fringe_rest).sortWith {case ((d1, _), (d2, _)) => d1 < d2}
|
||||
Dijkstra(lookup, sorted_fringe, dest, visited + key)
|
||||
}
|
||||
}
|
||||
case Nil => (0, List())
|
||||
}
|
||||
|
||||
def main(x: Array[String]): Unit = {
|
||||
val lookup = Map(
|
||||
"a" -> List((7.0, "b"), (9.0, "c"), (14.0, "f")),
|
||||
"b" -> List((10.0, "c"), (15.0, "d")),
|
||||
"c" -> List((11.0, "d"), (2.0, "f")),
|
||||
"d" -> List((6.0, "e")),
|
||||
"e" -> List((9.0, "f")),
|
||||
"f" -> Nil
|
||||
)
|
||||
val res = Dijkstra[String](lookup, List((0, List("a"))), "e", Set())
|
||||
println(res)
|
||||
}
|
||||
}
|
||||
57
Task/Dijkstras-algorithm/Scala/dijkstras-algorithm-2.scala
Normal file
57
Task/Dijkstras-algorithm/Scala/dijkstras-algorithm-2.scala
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import scala.collection.mutable
|
||||
|
||||
class Dijkstra[Key] {
|
||||
|
||||
type PathInfo = (Double, List[Key])
|
||||
type Path = List[Key]
|
||||
type MinHeap[PathInfo] = mutable.PriorityQueue[PathInfo]
|
||||
|
||||
final def dijkstra(weightedGraph: Map[Key, List[(Double, Key)]],
|
||||
start: Key,
|
||||
dest: Key)(implicit ord: Ordering[PathInfo]): PathInfo =
|
||||
dijkstraHelper(weightedGraph, mutable.PriorityQueue((0.0, List(start))), dest)
|
||||
|
||||
@annotation.tailrec
|
||||
private final def dijkstraHelper(weightedGraph: Map[Key, List[(Double, Key)]],
|
||||
fringe: MinHeap[PathInfo],
|
||||
dest: Key,
|
||||
visited: Set[Key] = Set.empty[Key])(implicit ord: Ordering[PathInfo]): PathInfo = {
|
||||
|
||||
def updateFringe(frng: MinHeap[PathInfo], currentDist: Double, currentPath: Path): MinHeap[PathInfo] =
|
||||
(currentPath : @unchecked) match {
|
||||
case keys @ key :: _ =>
|
||||
weightedGraph(key)
|
||||
.withFilter { case (_, k) => !visited.contains(k) }
|
||||
.map { case (d, k) => (currentDist + d, k :: keys) } // updated PathInfo's
|
||||
.foreach { p => frng.enqueue(p) }
|
||||
|
||||
frng
|
||||
}
|
||||
|
||||
if (fringe.isEmpty)
|
||||
(0, Nil)
|
||||
else {
|
||||
(fringe.dequeue() : @unchecked) match {
|
||||
case (dist, path @ `dest` :: _) =>
|
||||
(dist, path.reverse)
|
||||
|
||||
case (dist, path @ key :: _) =>
|
||||
dijkstraHelper(weightedGraph, updateFringe(fringe, dist, path), dest, visited + key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def main(x: Array[String]): Unit = {
|
||||
val weightedGraph = Map(
|
||||
"a" -> List((7.0, "b"), (9.0, "c"), (14.0, "f")),
|
||||
"b" -> List((10.0, "c"), (15.0, "d")),
|
||||
"c" -> List((11.0, "d"), (2.0, "f")),
|
||||
"d" -> List((6.0, "e")),
|
||||
"e" -> List((9.0, "f")),
|
||||
"f" -> Nil
|
||||
)
|
||||
|
||||
val res = dijkstra[String](weightedGraph, "a", "e")
|
||||
println(res)
|
||||
}
|
||||
}
|
||||
91
Task/Dijkstras-algorithm/Sidef/dijkstras-algorithm.sidef
Normal file
91
Task/Dijkstras-algorithm/Sidef/dijkstras-algorithm.sidef
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
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}"
|
||||
89
Task/Dijkstras-algorithm/Swift/dijkstras-algorithm.swift
Normal file
89
Task/Dijkstras-algorithm/Swift/dijkstras-algorithm.swift
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
typealias WeightedEdge = (Int, Int, Int)
|
||||
|
||||
struct Grid<T> {
|
||||
var nodes: [Node<T>]
|
||||
|
||||
mutating func addNode(data: T) -> Int {
|
||||
nodes.append(Node(data: data, edges: []))
|
||||
|
||||
return nodes.count - 1
|
||||
}
|
||||
|
||||
mutating func createEdges(weights: [WeightedEdge]) {
|
||||
for (start, end, weight) in weights {
|
||||
nodes[start].edges.append((end, weight))
|
||||
nodes[end].edges.append((start, weight))
|
||||
}
|
||||
}
|
||||
|
||||
func findPath(start: Int, end: Int) -> ([Int], Int)? {
|
||||
var dist = Array(repeating: (Int.max, nil as Int?), count: nodes.count)
|
||||
var heap = Heap<State>(sort: { $0.cost < $1.cost })
|
||||
|
||||
dist[start] = (0, nil)
|
||||
heap.insert(State(node: start, cost: 0))
|
||||
|
||||
while let state = heap.remove(at: 0) {
|
||||
if state.node == end {
|
||||
var path = [end]
|
||||
var currentDist = dist[end]
|
||||
|
||||
while let prev = currentDist.1 {
|
||||
path.append(prev)
|
||||
currentDist = dist[prev]
|
||||
}
|
||||
|
||||
return (path.reversed(), state.cost)
|
||||
}
|
||||
|
||||
guard state.cost <= dist[state.node].0 else {
|
||||
continue
|
||||
}
|
||||
|
||||
for edge in nodes[state.node].edges {
|
||||
let next = State(node: edge.0, cost: state.cost + edge.1)
|
||||
|
||||
if next.cost < dist[next.node].0 {
|
||||
dist[next.node] = (next.cost, state.node)
|
||||
heap.insert(next)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
struct Node<T> {
|
||||
var data: T
|
||||
var edges: [(Int, Int)]
|
||||
}
|
||||
|
||||
struct State {
|
||||
var node: Int
|
||||
var cost: Int
|
||||
}
|
||||
|
||||
var grid = Grid<String>(nodes: [])
|
||||
|
||||
let (a, b, c, d, e, f) = (
|
||||
grid.addNode(data: "a"),
|
||||
grid.addNode(data: "b"),
|
||||
grid.addNode(data: "c"),
|
||||
grid.addNode(data: "d"),
|
||||
grid.addNode(data: "e"),
|
||||
grid.addNode(data: "f")
|
||||
)
|
||||
|
||||
grid.createEdges(weights: [
|
||||
(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)
|
||||
])
|
||||
|
||||
guard let (path, cost) = grid.findPath(start: a, end: e) else {
|
||||
fatalError("Could not find path")
|
||||
}
|
||||
|
||||
print("Cost: \(cost)")
|
||||
print(path.map({ grid.nodes[$0].data }).joined(separator: " -> "))
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
data vertex <'a'..'f'>, to <vertex>
|
||||
|
||||
templates shortestPaths&{graph:}
|
||||
@: [];
|
||||
[ {to: $, distance: 0"1", path:[]} ] -> #
|
||||
when <[](0)> do $@ !
|
||||
otherwise
|
||||
def closest: $ ... -> ..=Min&{by: :(distance:), select: :()};
|
||||
$closest -> ..|@: $;
|
||||
def path: [ $closest.path..., $closest.to ];
|
||||
[ $... -> \(<?($.to <~=$closest.to>)> $!\),
|
||||
$graph... -> \(<?($.edge(1) <=$closest.to>) ?($@shortestPaths <~[<{to: <=$.edge(2)>}>]>)> $!\)
|
||||
-> { to: $.edge(2), distance: $.cost + $closest.distance, path: $path} ] -> #
|
||||
end shortestPaths
|
||||
|
||||
def edges: [
|
||||
{ edge: [vertex´'a', vertex´'b'], cost: 7"1" },
|
||||
{ edge: [vertex´'a', vertex´'c'], cost: 9"1" },
|
||||
{ edge: [vertex´'a', vertex´'f'], cost: 14"1" },
|
||||
{ edge: [vertex´'b', vertex´'c'], cost: 10"1" },
|
||||
{ edge: [vertex´'b', vertex´'d'], cost: 15"1" },
|
||||
{ edge: [vertex´'c', vertex´'d'], cost: 11"1" },
|
||||
{ edge: [vertex´'c', vertex´'f'], cost: 2"1" },
|
||||
{ edge: [vertex´'d', vertex´'e'], cost: 6"1" },
|
||||
{ edge: [vertex´'e', vertex´'f'], cost: 9"1" }];
|
||||
|
||||
def fromA: vertex´'a' -> shortestPaths&{graph: $edges};
|
||||
|
||||
$fromA... -> \(<{to:<=vertex´'e'>}> $!\) -> 'Shortest path from $.path(1); to $.to; is distance $.distance; via $.path(2..last);
|
||||
' -> !OUT::write
|
||||
|
||||
$fromA... -> \(<{to:<=vertex´'f'>}> $!\) -> 'Shortest path from $.path(1); to $.to; is distance $.distance; via $.path(2..last);
|
||||
' -> !OUT::write
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
data cost <"1">, distance <"1">
|
||||
data vertex <'[a-f]'>, to <vertex>, from <vertex>, path <[<vertex>* VOID]>
|
||||
|
||||
templates shortestPaths&{graph:}
|
||||
@: {||};
|
||||
{| {to: $, distance: 0"1", path:[]} |} -> #
|
||||
when <?($::count <=0>)> do $@ !
|
||||
otherwise
|
||||
def closest: $ ... -> ..=Min&{by: :(distance:), select: :()};
|
||||
@: ($@ union {|$closest|});
|
||||
def path: [ $closest.path..., $closest.to ];
|
||||
{| ($ notMatching {| $closest({to:}) |})...,
|
||||
(($graph matching {| $closest({from: §.to}) |}) notMatching $@({to:}))...
|
||||
-> { to: $.to, distance: $.cost + $closest.distance, path: $path}
|
||||
|} -> #
|
||||
end shortestPaths
|
||||
|
||||
def edges: {|
|
||||
{ from: vertex´'a', to: vertex´'b', cost: 7"1" },
|
||||
{ from: vertex´'a', to: vertex´'c', cost: 9"1" },
|
||||
{ from: vertex´'a', to: vertex´'f', cost: 14"1" },
|
||||
{ from: vertex´'b', to: vertex´'c', cost: 10"1" },
|
||||
{ from: vertex´'b', to: vertex´'d', cost: 15"1" },
|
||||
{ from: vertex´'c', to: vertex´'d', cost: 11"1" },
|
||||
{ from: vertex´'c', to: vertex´'f', cost: 2"1" },
|
||||
{ from: vertex´'d', to: vertex´'e', cost: 6"1" },
|
||||
{ from: vertex´'e', to: vertex´'f', cost: 9"1" }
|
||||
|};
|
||||
|
||||
def fromA: vertex´'a' -> shortestPaths&{graph: $edges};
|
||||
|
||||
($fromA matching {|{to:vertex´'e'}|})... -> 'Shortest path from $.path(1); to $.to; is distance $.distance; via $.path(2..last);
|
||||
' -> !OUT::write
|
||||
|
||||
($fromA matching {|{to:vertex´'f'}|})... -> 'Shortest path from $.path(1); to $.to; is distance $.distance; via $.path(2..last);
|
||||
' -> !OUT::write
|
||||
38
Task/Dijkstras-algorithm/Tcl/dijkstras-algorithm-1.tcl
Normal file
38
Task/Dijkstras-algorithm/Tcl/dijkstras-algorithm-1.tcl
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
proc dijkstra {graph origin} {
|
||||
# Initialize
|
||||
dict for {vertex distmap} $graph {
|
||||
dict set dist $vertex Inf
|
||||
dict set path $vertex {}
|
||||
}
|
||||
dict set dist $origin 0
|
||||
dict set path $origin [list $origin]
|
||||
|
||||
while {[dict size $graph]} {
|
||||
# Find unhandled node with least weight
|
||||
set d Inf
|
||||
dict for {uu -} $graph {
|
||||
if {$d > [set dd [dict get $dist $uu]]} {
|
||||
set u $uu
|
||||
set d $dd
|
||||
}
|
||||
}
|
||||
|
||||
# No such node; graph must be disconnected
|
||||
if {$d == Inf} break
|
||||
|
||||
# Update the weights for nodes lead to by the node we've picked
|
||||
dict for {v dd} [dict get $graph $u] {
|
||||
if {[dict exists $graph $v]} {
|
||||
set alt [expr {$d + $dd}]
|
||||
if {$alt < [dict get $dist $v]} {
|
||||
dict set dist $v $alt
|
||||
dict set path $v [list {*}[dict get $path $u] $v]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Remove chosen node from graph still to be handled
|
||||
dict unset graph $u
|
||||
}
|
||||
return [list $dist $path]
|
||||
}
|
||||
16
Task/Dijkstras-algorithm/Tcl/dijkstras-algorithm-2.tcl
Normal file
16
Task/Dijkstras-algorithm/Tcl/dijkstras-algorithm-2.tcl
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
proc makeUndirectedGraph arcs {
|
||||
# Assume that all nodes are connected to something
|
||||
foreach arc $arcs {
|
||||
lassign $arc v1 v2 cost
|
||||
dict set graph $v1 $v2 $cost
|
||||
dict set graph $v2 $v1 $cost
|
||||
}
|
||||
return $graph
|
||||
}
|
||||
set arcs {
|
||||
{a b 7} {a c 9} {b c 10} {b d 15} {c d 11}
|
||||
{d e 6} {a f 14} {c f 2} {e f 9}
|
||||
}
|
||||
lassign [dijkstra [makeUndirectedGraph $arcs] "a"] costs path
|
||||
puts "path from a to e costs [dict get $costs e]"
|
||||
puts "route from a to e is: [join [dict get $path e] { -> }]"
|
||||
175
Task/Dijkstras-algorithm/VBA/dijkstras-algorithm.vba
Normal file
175
Task/Dijkstras-algorithm/VBA/dijkstras-algorithm.vba
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
Class Branch
|
||||
Public from As Node '[according to Dijkstra the first Node should be closest to P]
|
||||
Public towards As Node
|
||||
Public length As Integer '[directed length!]
|
||||
Public distance As Integer '[from P to farthest node]
|
||||
Public key As String
|
||||
Class Node
|
||||
Public key As String
|
||||
Public correspondingBranch As Branch
|
||||
Const INFINITY = 32767
|
||||
Private Sub Dijkstra(Nodes As Collection, Branches As Collection, P As Node, Optional Q As Node)
|
||||
'Dijkstra, E. W. (1959). "A note on two problems in connexion with graphs".
|
||||
'Numerische Mathematik. 1: 269–271. doi:10.1007/BF01386390.
|
||||
'http://www-m3.ma.tum.de/twiki/pub/MN0506/WebHome/dijkstra.pdf
|
||||
'Problem 2. Find the path of minimum total length between two given nodes
|
||||
'P and Q.
|
||||
'We use the fact that, if R is a node on the minimal path from P to Q, knowledge
|
||||
'of the latter implies the knowledge of the minimal path from P to A. In the
|
||||
'solution presented, the minimal paths from P to the other nodes are constructed
|
||||
'in order of increasing length until Q is reached.
|
||||
'In the course of the solution the nodes are subdivided into three sets:
|
||||
'A. the nodes for which the path of minimum length from P is known; nodes
|
||||
'will be added to this set in order of increasing minimum path length from node P;
|
||||
'[comments in square brackets are not by Dijkstra]
|
||||
Dim a As New Collection '[of nodes (vertices)]
|
||||
'B. the nodes from which the next node to be added to set A will be selected;
|
||||
'this set comprises all those nodes that are connected to at least one node of
|
||||
'set A but do not yet belong to A themselves;
|
||||
Dim b As New Collection '[of nodes (vertices)]
|
||||
'C. the remaining nodes.
|
||||
Dim c As New Collection '[of nodes (vertices)]
|
||||
'The Branches are also subdivided into three sets:
|
||||
'I the Branches occurring in the minimal paths from node P to the nodes
|
||||
'in set A;
|
||||
Dim I As New Collection '[of Branches (edges)]
|
||||
'II the Branches from which the next branch to be placed in set I will be
|
||||
'selected; one and only one branch of this set will lead to each node in set B;
|
||||
Dim II As New Collection '[of Branches (edges)]
|
||||
'III. the remaining Branches (rejected or not yet considered).
|
||||
Dim III As New Collection '[of Branches (edges)]
|
||||
Dim u As Node, R_ As Node, dist As Integer
|
||||
'To start with, all nodes are in set C and all Branches are in set III. We now
|
||||
'transfer node P to set A and from then onwards repeatedly perform the following
|
||||
'steps.
|
||||
For Each n In Nodes
|
||||
c.Add n, n.key
|
||||
Next n
|
||||
For Each e In Branches
|
||||
III.Add e, e.key
|
||||
Next e
|
||||
a.Add P, P.key
|
||||
c.Remove P.key
|
||||
Set u = P
|
||||
Do
|
||||
'Step 1. Consider all Branches r connecting the node just transferred to set A
|
||||
'with nodes R in sets B or C. If node R belongs to set B, we investigate whether
|
||||
'the use of branch r gives rise to a shorter path from P to R than the known
|
||||
'path that uses the corresponding branch in set II. If this is not so, branch r is
|
||||
'rejected; if, however, use of branch r results in a shorter connexion between P
|
||||
'and R than hitherto obtained, it replaces the corresponding branch in set II
|
||||
'and the latter is rejected. If the node R belongs to set C, it is added to set B and
|
||||
'branch r is added to set II.
|
||||
For Each r In III
|
||||
If r.from Is u Then
|
||||
Set R_ = r.towards
|
||||
If Belongs(R_, c) Then
|
||||
c.Remove R_.key
|
||||
b.Add R_, R_.key
|
||||
Set R_.correspondingBranch = r
|
||||
If u.correspondingBranch Is Nothing Then
|
||||
R_.correspondingBranch.distance = r.length
|
||||
Else
|
||||
R_.correspondingBranch.distance = u.correspondingBranch.distance + r.length
|
||||
End If
|
||||
III.Remove r.key '[not mentioned by Dijkstra ...]
|
||||
II.Add r, r.key
|
||||
Else
|
||||
If Belongs(R_, b) Then '[initially B is empty ...]
|
||||
If R_.correspondingBranch.distance > u.correspondingBranch.distance + r.length Then
|
||||
II.Remove R_.correspondingBranch.key
|
||||
II.Add r, r.key
|
||||
Set R_.correspondingBranch = r '[needed in step 2.]
|
||||
R_.correspondingBranch.distance = u.correspondingBranch.distance + r.length
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Next r
|
||||
'Step 2. Every node in set B can be connected to node P in only one way
|
||||
'if we restrict ourselves to Branches from set I and one from set II. In this sense
|
||||
'each node in set B has a distance from node P: the node with minimum distance
|
||||
'from P is transferred from set B to set A, and the corresponding branch is transferred
|
||||
'from set II to set I. We then return to step I and repeat the process
|
||||
'until node Q is transferred to set A. Then the solution has been found.
|
||||
dist = INFINITY
|
||||
Set u = Nothing
|
||||
For Each n In b
|
||||
If dist > n.correspondingBranch.distance Then
|
||||
dist = n.correspondingBranch.distance
|
||||
Set u = n
|
||||
End If
|
||||
Next n
|
||||
b.Remove u.key
|
||||
a.Add u, u.key
|
||||
II.Remove u.correspondingBranch.key
|
||||
I.Add u.correspondingBranch, u.correspondingBranch.key
|
||||
Loop Until IIf(Q Is Nothing, a.Count = Nodes.Count, u Is Q)
|
||||
If Not Q Is Nothing Then GetPath Q
|
||||
End Sub
|
||||
Private Function Belongs(n As Node, col As Collection) As Boolean
|
||||
Dim obj As Node
|
||||
On Error GoTo err
|
||||
Belongs = True
|
||||
Set obj = col(n.key)
|
||||
Exit Function
|
||||
err:
|
||||
Belongs = False
|
||||
End Function
|
||||
Private Sub GetPath(Target As Node)
|
||||
Dim path As String
|
||||
If Target.correspondingBranch Is Nothing Then
|
||||
path = "no path"
|
||||
Else
|
||||
path = Target.key
|
||||
Set u = Target
|
||||
Do While Not u.correspondingBranch Is Nothing
|
||||
path = u.correspondingBranch.from.key & " " & path
|
||||
Set u = u.correspondingBranch.from
|
||||
Loop
|
||||
Debug.Print u.key, Target.key, Target.correspondingBranch.distance, path
|
||||
End If
|
||||
End Sub
|
||||
Public Sub test()
|
||||
Dim a As New Node, b As New Node, c As New Node, d As New Node, e As New Node, f As New Node
|
||||
Dim ab As New Branch, ac As New Branch, af As New Branch, bc As New Branch, bd As New Branch
|
||||
Dim cd As New Branch, cf As New Branch, de As New Branch, ef As New Branch
|
||||
Set ab.from = a: Set ab.towards = b: ab.length = 7: ab.key = "ab": ab.distance = INFINITY
|
||||
Set ac.from = a: Set ac.towards = c: ac.length = 9: ac.key = "ac": ac.distance = INFINITY
|
||||
Set af.from = a: Set af.towards = f: af.length = 14: af.key = "af": af.distance = INFINITY
|
||||
Set bc.from = b: Set bc.towards = c: bc.length = 10: bc.key = "bc": bc.distance = INFINITY
|
||||
Set bd.from = b: Set bd.towards = d: bd.length = 15: bd.key = "bd": bd.distance = INFINITY
|
||||
Set cd.from = c: Set cd.towards = d: cd.length = 11: cd.key = "cd": cd.distance = INFINITY
|
||||
Set cf.from = c: Set cf.towards = f: cf.length = 2: cf.key = "cf": cf.distance = INFINITY
|
||||
Set de.from = d: Set de.towards = e: de.length = 6: de.key = "de": de.distance = INFINITY
|
||||
Set ef.from = e: Set ef.towards = f: ef.length = 9: ef.key = "ef": ef.distance = INFINITY
|
||||
a.key = "a"
|
||||
b.key = "b"
|
||||
c.key = "c"
|
||||
d.key = "d"
|
||||
e.key = "e"
|
||||
f.key = "f"
|
||||
Dim testNodes As New Collection
|
||||
Dim testBranches As New Collection
|
||||
testNodes.Add a, "a"
|
||||
testNodes.Add b, "b"
|
||||
testNodes.Add c, "c"
|
||||
testNodes.Add d, "d"
|
||||
testNodes.Add e, "e"
|
||||
testNodes.Add f, "f"
|
||||
testBranches.Add ab, "ab"
|
||||
testBranches.Add ac, "ac"
|
||||
testBranches.Add af, "af"
|
||||
testBranches.Add bc, "bc"
|
||||
testBranches.Add bd, "bd"
|
||||
testBranches.Add cd, "cd"
|
||||
testBranches.Add cf, "cf"
|
||||
testBranches.Add de, "de"
|
||||
testBranches.Add ef, "ef"
|
||||
Debug.Print "From", "To", "Distance", "Path"
|
||||
'[Call Dijkstra with target:]
|
||||
Dijkstra testNodes, testBranches, a, e
|
||||
'[Call Dijkstra without target computes paths to all reachable nodes:]
|
||||
Dijkstra testNodes, testBranches, a
|
||||
GetPath f
|
||||
End Sub
|
||||
152
Task/Dijkstras-algorithm/Wren/dijkstras-algorithm.wren
Normal file
152
Task/Dijkstras-algorithm/Wren/dijkstras-algorithm.wren
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
import "/dynamic" for Tuple
|
||||
import "/trait" for Comparable
|
||||
import "/sort" for Cmp, Sort
|
||||
import "/set" for Set
|
||||
|
||||
var Edge = Tuple.create("Edge", ["v1", "v2", "dist"])
|
||||
|
||||
// One vertex of the graph, complete with mappings to neighboring vertices
|
||||
class Vertex is Comparable {
|
||||
static map { __map } // maps a name to its corresponding Vertex
|
||||
|
||||
construct new(name) {
|
||||
_name = name
|
||||
_dist = Num.maxSafeInteger // assumed to be infinity
|
||||
_prev = null
|
||||
_neighbors = {}
|
||||
if (!__map) __map = {}
|
||||
__map[name] = this
|
||||
}
|
||||
|
||||
name { _name }
|
||||
dist { _dist }
|
||||
dist=(d) { _dist = d }
|
||||
prev { _prev }
|
||||
prev=(v) { _prev = v }
|
||||
neighbors { _neighbors }
|
||||
|
||||
printPath() {
|
||||
if (this == _prev) {
|
||||
System.write(_name)
|
||||
} else if (!_prev) {
|
||||
System.write("%(_name)(unreached)")
|
||||
} else {
|
||||
_prev.printPath()
|
||||
System.write(" -> %(_name)(%(_dist))")
|
||||
}
|
||||
}
|
||||
|
||||
compare(other) {
|
||||
if (_dist == other.dist) return Cmp.string.call(_name, other.name)
|
||||
return Cmp.num.call(_dist, other.dist)
|
||||
}
|
||||
|
||||
toString { "(%(_name), %(_dist))" }
|
||||
}
|
||||
|
||||
class Graph {
|
||||
construct new(edges, directed, showAllPaths) {
|
||||
_graph = {}
|
||||
// one pass to find all vertices
|
||||
for (e in edges) {
|
||||
if (!_graph.containsKey(e.v1)) _graph[e.v1] = Vertex.new(e.v1)
|
||||
if (!_graph.containsKey(e.v2)) _graph[e.v2] = Vertex.new(e.v2)
|
||||
}
|
||||
|
||||
// another pass to set neighboring vertices
|
||||
for (e in edges) {
|
||||
_graph[e.v1].neighbors[_graph[e.v2].name] = e.dist
|
||||
// also do this for an undirected graph if applicable
|
||||
if (!directed) _graph[e.v2].neighbors[_graph[e.v1].name] = e.dist
|
||||
}
|
||||
_showAllPaths = showAllPaths
|
||||
_directed = directed
|
||||
}
|
||||
|
||||
// Runs dijkstra using a specified source vertex
|
||||
dijkstra(startName) {
|
||||
if (!_graph.containsKey(startName)) {
|
||||
System.print("Graph doesn't contain start vertex '%(startName)'")
|
||||
return
|
||||
}
|
||||
var source = _graph[startName]
|
||||
var q = Set.new()
|
||||
|
||||
// set-up vertices
|
||||
for (v in _graph.values) {
|
||||
v.prev = (v == source) ? source : null
|
||||
v.dist = (v == source) ? 0 : Num.maxSafeInteger
|
||||
q.add(v.name)
|
||||
}
|
||||
dijkstra_(q)
|
||||
}
|
||||
|
||||
// Implementation of dijkstra's algorithm using a (simulated) tree set
|
||||
dijkstra_(q) {
|
||||
while (!q.isEmpty) {
|
||||
var qq = q.toList
|
||||
Sort.heap(qq)
|
||||
// vertex with shortest distance (first iteration will return source)
|
||||
var u = Vertex.map[qq[0]]
|
||||
q.remove(qq[0])
|
||||
// if distance is infinite we can ignore 'u'
|
||||
// (and any other remaining vertices) since they are unreachable
|
||||
if (u.dist == Num.maxSafeInteger) break
|
||||
|
||||
// look at distances to each neighbor
|
||||
for (a in u.neighbors) {
|
||||
var v = Vertex.map[a.key] // the neighbor in this iteration
|
||||
var alternateDist = u.dist + a.value
|
||||
if (alternateDist < v.dist) { // shorter path to neighbor found
|
||||
v.dist = alternateDist
|
||||
v.prev = u
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the path from the source to every vertex
|
||||
// (output order is not guaranteed)
|
||||
printAllPaths_() {
|
||||
for (v in _graph.values) {
|
||||
v.printPath()
|
||||
System.print()
|
||||
}
|
||||
System.print()
|
||||
}
|
||||
|
||||
// Prints a path from the source to the specified vertex
|
||||
printPath(endName) {
|
||||
if (!_graph.containsKey(endName)) {
|
||||
System.print("Graph doesn't contain end vertex '%(endName)'")
|
||||
return
|
||||
}
|
||||
System.write(_directed ? "Directed : " : "Undirected : ")
|
||||
_graph[endName].printPath()
|
||||
System.print()
|
||||
if (_showAllPaths) printAllPaths_() else System.print()
|
||||
}
|
||||
}
|
||||
|
||||
var GRAPH = [
|
||||
Edge.new("a", "b", 7),
|
||||
Edge.new("a", "c", 9),
|
||||
Edge.new("a", "f", 14),
|
||||
Edge.new("b", "c", 10),
|
||||
Edge.new("b", "d", 15),
|
||||
Edge.new("c", "d", 11),
|
||||
Edge.new("c", "f", 2),
|
||||
Edge.new("d", "e", 6),
|
||||
Edge.new("e", "f", 9)
|
||||
]
|
||||
|
||||
var START = "a"
|
||||
var END = "e"
|
||||
|
||||
var g = Graph.new(GRAPH, true, false) // directed
|
||||
g.dijkstra(START)
|
||||
g.printPath(END)
|
||||
|
||||
g = Graph.new(GRAPH, false, false) // undirected
|
||||
g.dijkstra(START)
|
||||
g.printPath(END)
|
||||
22
Task/Dijkstras-algorithm/Zkl/dijkstras-algorithm-1.zkl
Normal file
22
Task/Dijkstras-algorithm/Zkl/dijkstras-algorithm-1.zkl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const INF=(0).MAX;
|
||||
fcn dijkstra(graph,start,dst){
|
||||
Q :=graph.copy();
|
||||
prev:=graph.keys.pump(Dictionary().add.fp1(Void));
|
||||
dist:=graph.keys.pump(Dictionary().add.fp1(INF));
|
||||
dist[start]=0;
|
||||
while(Q){
|
||||
Q.reduce('wrap(min,[(v,_)],ru){
|
||||
if((d:=dist[v])<min){ ru.set(v); d } else min },
|
||||
INF,ru:=Ref(Void));
|
||||
if(not u:=ru.value) return("Can't get there");
|
||||
if(u==dst){
|
||||
S:=List(); do{ S.append(u); u=prev[u]; }while(u);
|
||||
return(S.reverse());
|
||||
}
|
||||
Q.del(u);
|
||||
foreach v,len in (graph[u]){ // (neighborVertex,len to neighbor)...
|
||||
alt:=dist[u] + len;
|
||||
if(alt<dist[v]){ dist[v]=alt; prev[v]=u; }
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Task/Dijkstras-algorithm/Zkl/dijkstras-algorithm-2.zkl
Normal file
10
Task/Dijkstras-algorithm/Zkl/dijkstras-algorithm-2.zkl
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
graph:=Dictionary( // directed graph
|
||||
"a", T(T("b", 7.0), T("c", 9.0), T("f",14.0)),
|
||||
"b", T(T("c",10.0), T("d",15.0)),
|
||||
"c", T(T("d",11.0), T("f", 2.0)),
|
||||
"d", T(T("e", 6.0)),
|
||||
"e", T(T("f", 9.0)),
|
||||
"f", T,
|
||||
);
|
||||
dijkstra(graph,"a","e").println();
|
||||
dijkstra(graph,"e","a").println();
|
||||
Loading…
Add table
Add a link
Reference in a new issue