1 module dkh.graph.dijkstra; 2 3 import dkh.algorithm, dkh.container.radixheap; 4 5 struct DijkstraInfo(T) { 6 T[] dist; 7 int[] from; 8 this(int n, T inf) { 9 dist = new T[n]; dist[] = inf; 10 from = new int[n]; 11 } 12 } 13 14 DijkstraInfo!D dijkstra(D, T)(T g, int s, D inf = D.max) { 15 import std.conv : to; 16 import std.typecons : Tuple; 17 import std.container : make, Array, heapify; 18 import std.container.binaryheap : BinaryHeap; 19 import std.traits : isIntegral; 20 21 int V = g.length.to!int; 22 auto dijk = DijkstraInfo!D(V, inf); 23 with (dijk) { 24 alias P = Tuple!(int, "to", D, "dist"); 25 auto q = (){ 26 static if (isIntegral!D) { 27 return RadixHeap!(P, "a.dist")(); 28 } else { 29 return heapify!"a.dist>b.dist"(make!(Array!P)); 30 } 31 }(); 32 q.insert(P(s, D(0))); 33 dist[s] = D(0); 34 from[s] = -1; 35 while (!q.empty) { 36 P p = q.front; q.removeFront(); 37 if (dist[p.to] < p.dist) continue; 38 foreach (e; g[p.to]) { 39 if (p.dist+e.dist < dist[e.to]) { 40 dist[e.to] = p.dist+e.dist; 41 from[e.to] = p.to; 42 q.insert(P(e.to, dist[e.to])); 43 } 44 } 45 } 46 } 47 return dijk; 48 } 49 50 DijkstraInfo!D dijkstraDense(D, T)(T g, int s, D inf = D.max) { 51 import std.conv : to; 52 import std.typecons : Tuple; 53 import std.container : make, Array, heapify; 54 import std.range : enumerate; 55 import std.algorithm : filter; 56 57 int V = g.length.to!int; 58 auto dijk = DijkstraInfo!D(V, inf); 59 with (dijk) { 60 alias P = Tuple!(int, "to", D, "dist"); 61 62 bool[] used = new bool[](V); 63 dist[s] = D(0); 64 from[s] = -1; 65 while (true) { 66 //todo can optimize 67 auto rng = dist.enumerate.filter!(a => !used[a.index]); 68 if (rng.empty) break; 69 auto nx = rng.minimum!"a.value < b.value"; 70 used[nx.index] = true; 71 P p = P(nx.index.to!int, nx.value); 72 if (p.dist == inf) continue; 73 foreach (e; g[p.to]) { 74 if (p.dist+e.dist < dist[e.to]) { 75 dist[e.to] = p.dist+e.dist; 76 from[e.to] = p.to; 77 } 78 } 79 } 80 } 81 return dijk; 82 } 83 84 unittest { 85 import std.algorithm, std.conv, std.stdio, std.range; 86 import std.random; 87 import std.typecons; 88 89 alias E = Tuple!(int, "to", int, "dist"); 90 91 void f(alias pred)() { 92 int n = uniform(1, 50); 93 int m = uniform(1, 500); 94 E[][] g = new E[][n]; 95 int[][] dist = new int[][](n, n); 96 foreach (i, ref v; dist) { 97 v[] = 10^^9; 98 } 99 iota(n).each!(i => dist[i][i] = 0); 100 foreach (i; 0..m) { 101 int a = uniform(0, n); 102 int b = uniform(0, n); 103 int c = uniform(0, 1000); 104 g[a] ~= E(b, c); 105 dist[a][b] = min(dist[a][b], c); 106 } 107 foreach (k; 0..n) { 108 foreach (i; 0..n) { 109 foreach (j; 0..n) { 110 dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); 111 } 112 } 113 } 114 foreach (i; 0..n) { 115 auto dijk = pred!int(g, i, 10^^9); 116 foreach (j; 0..n) { 117 assert(dist[i][j] == dijk.dist[j]); 118 } 119 assert(dijk.from[i] == -1); 120 foreach (j; 0..n) { 121 if (i == j) continue; 122 if (dist[i][j] == 10^^9) continue; 123 int b = dijk.from[j]; 124 assert(dijk.dist[j] == dist[i][b]+dist[b][j]); 125 } 126 } 127 } 128 import dkh.stopwatch; 129 auto ti = benchmark!(f!dijkstra, f!dijkstraDense)(100); 130 writeln("Dijkstra Random100: ", ti[].map!(a => a.toMsecs())); 131 } 132 133 unittest { 134 import std.algorithm, std.conv, std.stdio, std.range; 135 import std.random; 136 import std.typecons; 137 138 alias E = Tuple!(int, "to", int, "dist"); 139 140 void f(alias pred)() { 141 int n = uniform(1, 50); 142 int m = uniform(1, 500); 143 E[][] g = new E[][n]; 144 int[][] dist = new int[][](n, n); 145 foreach (i, ref v; dist) { 146 v[] = int.max; 147 } 148 iota(n).each!(i => dist[i][i] = 0); 149 foreach (i; 0..m) { 150 int a = uniform(0, n); 151 int b = uniform(0, n); 152 int c = uniform(0, 1000); 153 g[a] ~= E(b, c); 154 dist[a][b] = min(dist[a][b], c); 155 } 156 foreach (k; 0..n) { 157 foreach (i; 0..n) { 158 foreach (j; 0..n) { 159 if (dist[i][k] == int.max) continue; 160 if (dist[k][j] == int.max) continue; 161 dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); 162 } 163 } 164 } 165 foreach (i; 0..n) { 166 auto dijk = pred!int(g, i); 167 foreach (j; 0..n) { 168 assert(dist[i][j] == dijk.dist[j]); 169 } 170 assert(dijk.from[i] == -1); 171 foreach (j; 0..n) { 172 if (i == j) continue; 173 if (dist[i][j] == int.max) continue; 174 int b = dijk.from[j]; 175 assert(dijk.dist[j] == dist[i][b]+dist[b][j]); 176 } 177 } 178 } 179 import dkh.stopwatch; 180 auto ti = benchmark!(f!dijkstra, f!dijkstraDense)(100); 181 writeln("Dijkstra INF Random100: ", ti[].map!(a => a.toMsecs())); 182 }