views:

29

answers:

1

I'm working on a directed network problem and trying to compute all valid paths between two points. I need a way to look at paths up to 30 "trips" (represented by an [origin, destination] pair) in length. The full route is then composed of a series of these pairs:

route = [[start, city2], [city2, city3], [city3, city4], [city4, city5], [city5, city6], [city6, city7], [city7, city8], [city8, stop]]

So far my best solution is as follows:

    def numRoutes(graph, start, stop, minStops, maxStops):
    routes = []

    route = [[start, stop]]
    if distance(graph, route) != "NO SUCH ROUTE" and len(route) >= minStops and len(route) <= maxStops: 
            routes.append(route)

    if maxStops >= 2:
        for city2 in routesFromCity(graph, start):
            route = [[start, city2],[city2, stop]]
            if distance(graph, route) != "NO SUCH ROUTE" and len(route) >= minStops and len(route) <= maxStops: 
                routes.append(route)
    if maxStops >= 3:       
        for city2 in routesFromCity(graph, start):
            for city3 in routesFromCity(graph, city2):
                route = [[start, city2], [city2, city3], [city3, stop]]
                if distance(graph, route) != "NO SUCH ROUTE" and len(route) >= minStops and len(route) <= maxStops:
                    routes.append(route)

    if maxStops >= 4:
        for city2 in routesFromCity(graph, start):
            for city3 in routesFromCity(graph, city2):
                for city4 in routesFromCity(graph, city3):
                    route = [[start, city2], [city2, city3], [city3, city4], [city4, stop]]
                    if distance(graph, route) != "NO SUCH ROUTE" and len(route) >= minStops and len(route) <= maxStops:
                        routes.append(route)
    if maxStops >= 5:
        for city2 in routesFromCity(graph, start):
            for city3 in routesFromCity(graph, city2):
                for city4 in routesFromCity(graph, city3):
                    for city5 in routesFromCity(graph, city4):
                        route = [[start, city2], [city2, city3], [city3, city4], [city4, city5], [city5, stop]]
                        if distance(graph, route) != "NO SUCH ROUTE" and len(route) >= minStops and len(route) <= maxStops:
                            routes.append(route)
return routes

Where numRoutes is fed my network graph where numbers represent distances:

[[0, 5, 0, 5, 7], [0, 0, 4, 0, 0], [0, 0, 0, 8, 2], [0, 0, 8, 0, 6], [0, 3, 0, 0, 0]]

a start city, an end city and the parameters for the length of the routes.

distance checks if a route is viable and routesFromCity returns the attached nodes to each fed in city.

I have a feeling there's a far more efficient way to generate all of the routes especially as I move toward many more steps, but I can't seem to get anything else to work.

A: 

You could use a recursive function. Your maxStops can be a parameter and each time you call you decrease this by 1. When minStops is 0, you yield a result, When the maxStops is 0 you stop recursing.

Here is a code example:

def routesFromCity(x):
    for i in range(2, 10):
        yield x * i

def findRoutes(start, stop, minStops, maxStops):
    if start == stop:
        if minStops <= 0:
            yield []
    else:
        if maxStops > 0:
            for nextCity in routesFromCity(start):
                for route in findRoutes(nextCity, stop, minStops - 1, maxStops - 1):
                    yield [(start, nextCity)] + route

for route in findRoutes(1, 12, 2, 5):
    print route

Output:

[(1, 2), (2, 4), (4, 12)]
[(1, 2), (2, 6), (6, 12)]
[(1, 2), (2, 12)]
[(1, 3), (3, 6), (6, 12)]
[(1, 3), (3, 12)]
[(1, 4), (4, 12)]
[(1, 6), (6, 12)]
Mark Byers
Thanks for the response. I've gotten close to using that before but I don't see how to replace the nested for loops or how to construct the result in a way that maintains the structure.
Will
@Will: I've updated my answer to include a code example. I've replace the graph with a simple function that generates routes based on a simple algorithm, but you should pass a graph into the recursive function instead.
Mark Byers
@Mark Byers: This is perfect, but I want to include loops as well. So if I wanted the all the routes between 2 and 3, the results would include [[2,3],[3,2]], [[2,3],[3,2],[2,3],[3,2]], [[2,3],[3,2],[2,3],[3,2],[2,3],[3,2]] etc. Thanks again.
Will
@Will: The code I provided does allow loops. But I stop the recursion when the destination is reached. Just change it to allow the journey to continue even if you have already reached your destination. (i.e. remove the else keyword and fix the indentation).
Mark Byers
@Mark Byers: Got it! Thanks
Will