
Graph Search
#
# This finds shortest (acyclic) paths in a graph. Input consists of lines
# which are are arcs, then a --- separator, then pairs which are
# requests for the shortest path. The algorithm returns the cheapest
# acyclic path in the graph. If there are no negative arcs, this is
# also the cheapest path.
#
from graph import Graph
#from graphsimp import Graph
import sys
g = Graph()
some_neg = False
# See if cost1 >= cost2, accounting for either or both being "infinity", which
# can't be directly compared with a number using >=. (But can be
# with == and !=).
def ge(cost1, cost2):
"""Tell if cost1 >= cost2, allowing either to be the string "infinity" """
if cost1 == "infinity":
return True
elif cost2 == "infinity":
# We already know cost1 isn't infinity, so cost2 is larger.
return False
else:
return cost1 >= cost2
# See if cost1 > cost2, accounting for either or both being "infinity", which
# can't be directly compared with a number using >. (But can be
# with == and !=).
def gt(cost1, cost2):
"""Tell if cost1 > cost2, allowing either to be the string "infinity" """
return cost1 != cost2 and ge(cost1,cost2)
def search(source, to):
"""Find the best (cheapest) cost route from source to to. Print the route and cost"""
# Initial best cost is to go directly. Might be infinity, if there is no arc.
best_cost = g.weight(source, to)
best_route = [ source, to ]
# List of pending work. Each list item is a tuple of the path so far, a map
# representing those locations, and the cost.
seen = {}
seen[source] = 1
pending = [ ( [ source ], seen, 0) ]
# Go until we've tried everything.
while len(pending) > 0:
# Get the data at end of the list, then remove it from the list.
path, pmap, cost = pending[-1]
del pending[-1]
# See if we've got there.
if path[-1] == to:
# If this is a better cost, record it as the new best.
if gt(best_cost, cost):
best_route = path
best_cost = cost
# Since we have arrived, there's really no point in extending this path.
continue
# If there are no negative links and we're past the current best cost,
# this path won't help and we can stop.
if not some_neg and ge(cost, best_cost):
continue
# Now we need to extend the search one level. Find each possible successor
# which does not create a cycle.
for s in g.successors(path[-1]):
if not (s in pmap):
# Add an extension to the list.
newmap = pmap.copy()
newmap[s] = 1
pending.append((path + [s], newmap,
cost + g.weight(path[-1],s)))
# Print the results.
print (str(best_route)+":", best_cost)
# Load the graph arcs.
line = sys.stdin.readline()
while line:
if line == "---\n":
break
source, to, weight = line.split()
weight = int(weight)
g.link(source, to, weight)
if weight < 0:
some_neg = True
line = sys.stdin.readline()
# Process the length requests.
line = sys.stdin.readline()
while line:
source, to = line.split()
search(source, to)
line = sys.stdin.readline()