''' bidirectional dijkstra/search algorithm, mostly copied from NetworkX: http://networkx.lanl.gov/ NetworkX is free software; you can redistribute it and/or modify it under the terms of the LGPL (GNU Lesser General Public License) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Please see the license for more information. ''' import heapq, time, sys, random random.seed(1) print sys.version class Graph: def __init__(self): self.vertices = {} def add_edge(self, a, b, weight): for id_ in (a, b): if id_ not in self.vertices: self.vertices[id_] = Vertex(id_) va, vb = self.vertices[a], self.vertices[b] va.neighs.append((vb, weight)) vb.neighs.append((va, weight)) class Vertex: def __init__(self, id_): self.id_ = id_ self.neighs = [] def __repr__(self): return repr(self.id_) def bidirectional_dijkstra(G, source_id, target_id): source, target = G.vertices[source_id], G.vertices[target_id] if source == target: return (0.0, [source]) #Init: Forward Backward dists = [{}, {}]# dictionary of final distances paths = [{source:[source]}, {target:[target]}] # dictionary of paths fringe = [[], []] #heap of (distance, node) tuples for extracting next node to expand seen = [{source:0.0}, {target:0.0} ]#dictionary of distances to nodes seen #initialize fringe heap heapq.heappush(fringe[0], (0.0, source)) heapq.heappush(fringe[1], (0.0, target)) #variables to hold shortest discovered path #finaldist = 1e30000 finalpath = [] dir = 1 while fringe[0] and fringe[1]: # choose direction # dir == 0 is forward direction and dir == 1 is back dir = 1-dir # extract closest to expand (dist, v) = heapq.heappop(fringe[dir]) if v in dists[dir]: # Shortest path to v has already been found continue # update distance dists[dir][v] = dist #equal to seen[dir][v] if v in dists[1-dir]: # if we have scanned v in both directions we are done # we have now discovered the shortest path return (finaldist,finalpath) for w, weight in v.neighs: vwLength = dists[dir][v] + weight if w in dists[dir]: pass elif w not in seen[dir] or vwLength < seen[dir][w]: # relaxing seen[dir][w] = vwLength heapq.heappush(fringe[dir], (vwLength,w)) paths[dir][w] = paths[dir][v]+[w] if w in seen[0] and w in seen[1]: #see if this path is better than than the already #discovered shortest path totaldist = seen[0][w] + seen[1][w] if finalpath == [] or finaldist > totaldist: finaldist = totaldist revpath = paths[1][w][:] revpath.reverse() finalpath = paths[0][w] + revpath[1:] return None def make_graph(n): G = Graph() dirs = [(-1,0), (1,0), (0,1), (0,-1)] for u in range(n): for v in range(n): for dir in dirs: x, y = u+dir[0], v+dir[1] if 0 <= x < n and 0 <= y < n: G.add_edge((u,v), (x, y), random.randint(1,3)) return G if __name__ == '__main__': n = 300 if len(sys.argv) > 1: n = int(sys.argv[1]) t0 = time.time() G = make_graph(n) print 't0 %.2f' % (time.time()-t0) t1 = time.time() wt, nodes = bidirectional_dijkstra(G, (0,0), (n-1,n-1)) print 'wt', wt print 't1 %.2f' % (time.time()-t1)