73 lines
1.6 KiB
Dart
73 lines
1.6 KiB
Dart
|
import 'package:collection/collection.dart';
|
||
|
|
||
|
class Edge<T> {
|
||
|
final double cost;
|
||
|
final T destination;
|
||
|
|
||
|
Edge(this.cost, this.destination);
|
||
|
}
|
||
|
|
||
|
class Result<T> {
|
||
|
final double cost;
|
||
|
final T? predecessor;
|
||
|
final T item;
|
||
|
|
||
|
Result(this.cost, this.predecessor, this.item);
|
||
|
}
|
||
|
|
||
|
Iterable<Result<T>> dijkstra<T>(
|
||
|
T source, Iterable<Edge<T>> Function(T) neighbors) sync* {
|
||
|
var queue = PriorityQueue<Result<T>>((i0, i1) => i0.cost.compareTo(i1.cost));
|
||
|
|
||
|
Set<T> seen = {source};
|
||
|
queue.add(Result(0.0, null, source));
|
||
|
|
||
|
while (queue.isNotEmpty) {
|
||
|
var u = queue.removeFirst();
|
||
|
yield u;
|
||
|
|
||
|
for (var v in neighbors(u.item)) {
|
||
|
if (seen.contains(v.destination)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
seen.add(v.destination);
|
||
|
queue.add(Result(u.cost + v.cost, u.item, v.destination));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
List<T>? dijkstraPath<T>(
|
||
|
T source, T destination, Iterable<Edge<T>> Function(T) neighbors,
|
||
|
{double? maxCost}) {
|
||
|
if (source == destination) {
|
||
|
return [];
|
||
|
}
|
||
|
Map<T, T?> predecessor = {};
|
||
|
|
||
|
for (var r in dijkstra(source, neighbors)) {
|
||
|
predecessor[r.item] = r.predecessor;
|
||
|
if (maxCost != null && r.cost >= maxCost) {
|
||
|
return null;
|
||
|
}
|
||
|
if (r.item == destination) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var revPath = [destination];
|
||
|
while (true) {
|
||
|
var pred = predecessor[revPath.last];
|
||
|
|
||
|
if (pred == source) {
|
||
|
revPath.reverseRange(0, revPath.length);
|
||
|
return revPath;
|
||
|
} else if (pred == null) {
|
||
|
throw Exception(
|
||
|
"predecessor should not be null -- that would mean we missed source");
|
||
|
} else {
|
||
|
revPath.add(pred);
|
||
|
}
|
||
|
}
|
||
|
}
|