diff --git a/README.md b/README.md index 7d9e9c3..df58731 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Try to keep the interface and variable name consistent with the original book wh * [EdgeWeightedDigraph](algs4/edge_weighted_digraph.py) * [DijkstraSP](algs4/dijkstra_sp.py) * [AcyclicSP](algs4/acyclic_sp.py) - * [Bellman-FordSP](algs4/bellman_ford_sp.py) + * [BellmanFordSP](algs4/bellman_ford_sp.py) * 5 STRING diff --git a/algs4/acyclic_sp.py b/algs4/acyclic_sp.py new file mode 100644 index 0000000..188f43d --- /dev/null +++ b/algs4/acyclic_sp.py @@ -0,0 +1,35 @@ +from algs4.stack import Stack +from algs4.topological import Topological + +POSITIVE_INFINITY = 999999.0 + + +class AcyclicSP: + def __init__(self, g, s): + self.edgeTo = [None for _ in range(g.V)] + self.distTo = [float("inf") for _ in range(g.V)] + for v in range(g.V): + self.distTo[v] = POSITIVE_INFINITY + self.distTo[s] = 0.0 + top = Topological(g) + for e in top.order: + self.relax(e) + + def relax(self, e): + v, w = e.From(), e.To() + if self.distTo[w] > self.distTo[v] + e.weight: + self.distTo[w] = self.distTo[v] + e.weight + self.edgeTo[w] = e + + def has_path_to(self, v): + return self.distTo[v] < POSITIVE_INFINITY + + def path_to(self, v): + if not self.has_path_to(v): + return None + edges = Stack() + e = self.edgeTo[v] + while e != None: + edges.push(e) + e = self.edgeTo[e.From()] + return edges diff --git a/algs4/bellman_ford_sp.py b/algs4/bellman_ford_sp.py new file mode 100644 index 0000000..23810f5 --- /dev/null +++ b/algs4/bellman_ford_sp.py @@ -0,0 +1,64 @@ +from algs4.queue import Queue +from algs4.stack import Stack + +POSITIVE_INFINITY = 999999.0 + + +class DijkstraSP: + def __init__(self, g, s): + self.cost = 0 + self.cycle = None + self.edgeTo = [None for _ in range(g.V)] + self.distTo = [float("inf") for _ in range(g.V)] + self.onQ = [false for _ in range(g.V)] + for v in range(g.V): + self.distTo[v] = POSITIVE_INFINITY + self.distTo[s] = 0.0 + + self.queue = Queue() + self.queue.enqueue(s) + self.onQ[s] = True + while not self.queue.is_empty() and not self.has_negative_cycle(): + v = self.queue.dequeue() + self.onQ[v] = False + self.relax(g, v) + + def relax(self, g, v): + for e in g.adj[v]: + w = e.To() + if self.distTo[w] > self.distTo[v]+e.weight: + self.distTo[w] = self.distTo[v] + e.weight + self.edgeTo[w] = e + if not self.onQ[w]: + self.queue.enqueue(w) + self.onQ[w] = True + self.cost += 1 + if self.cost % g.V == 0: + self.find_negative_cycle() + if self.has_negative_cycle(): + return + + def find_negative_cycle(self): + V = len(self.edgeTo) + spt = EdgeWeightedDigraph(V) + for v in range(V): + if self.edgeTo[v] != None: + spt.add_edge(self.edgeTo[v]) + finder = EdgeWeightedDirectedCycle(spt) + self.cycle = finder.cycle() + + def has_negative_cycle(self): + return self.cycle != None + + def has_path_to(self, v): + return self.distTo[v] < POSITIVE_INFINITY + + def path_to(self, v): + if not self.has_path_to(v): + return None + edges = Stack() + e = self.edgeTo[v] + while e != None: + edges.push(e) + e = self.edgeTo[e.From()] + return edges