Ludium
Sign In
Introduction to Computational Thinking and Data Science
Optimization
01Optimization Models and the Knapsack Problem02Brute-Force Knapsack and the Exponential Power Set03Greedy Algorithms: One Function, Any Definition of Best04Lambda Keys and Why Greedy Can Miss the OptimumProblem set0/10MIT problem set0/2
01The Knapsack Search Tree: Every Combination, 2ⁿ Nodes02Recursive maxVal: An Exhaustive Search That Beats Greedy03Memoization: Turning Slow Fibonacci into fastFib04Overlapping Subproblems and the Memoized KnapsackProblem set0/10MIT problem set0/2
Graph Models
01Graphs as Models: Nodes, Edges and Euler's Seven Bridges02Coding a Graph in Python: Node, Edge, Digraph and Graph03Depth-First Search for the Shortest Path in a Graph04Breadth-First Search: A Queue of Paths, Fewest Hops FirstProblem set0/10MIT problem set0/4

Depth-First Search for the Shortest Path in a Graph

Why must depth-first search explore every cycle-free path before it can claim the shortest one, and how does it avoid looping forever?


Finger exercises

Short drills on what this video just taught. Write the code, run the checks, and reveal the answer only if you are stuck.

0 / 5 passed
Exercise 1 of 5

Which children can the search step to

To avoid going round a cycle, depth-first search never steps to a node that is already on the current path. Define nextSteps(graph, node, path) that returns the names of the children of node that are not on path (a list of nodes), in the order childrenOf lists them. The city graph from the video is built for you by buildCityGraph.

Given code — runs before yours
class Node(object):
    def __init__(self, name):
        """Assumes name is a string"""
        self.name = name
    def getName(self):
        return self.name
    def __str__(self):
        return self.name

class Edge(object):
    def __init__(self, src, dest):
        """Assumes src and dest are nodes"""
        self.src = src
        self.dest = dest
    def getSource(self):
        return self.src
    def getDestination(self):
        return self.dest
    def __str__(self):
        return self.src.getName() + '->' + self.dest.getName()

class Digraph(object):
    """edges is a dict mapping each node to a list of its children"""
    def __init__(self):
        self.edges = {}
    def addNode(self, node):
        if node in self.edges:
            raise ValueError('Duplicate node')
        else:
            self.edges[node] = []
    def addEdge(self, edge):
        src = edge.getSource()
        dest = edge.getDestination()
        if not (src in self.edges and dest in self.edges):
            raise ValueError('Node not in graph')
        self.edges[src].append(dest)
    def childrenOf(self, node):
        return self.edges[node]
    def hasNode(self, node):
        return node in self.edges
    def getNode(self, name):
        for n in self.edges:
            if n.getName() == name:
                return n
        raise NameError(name)
    def __str__(self):
        result = ''
        for src in self.edges:
            for dest in self.edges[src]:
                result = result + src.getName() + '->' + dest.getName() + '\n'
        return result[:-1]

class Graph(Digraph):
    def addEdge(self, edge):
        Digraph.addEdge(self, edge)
        rev = Edge(edge.getDestination(), edge.getSource())
        Digraph.addEdge(self, rev)

def buildCityGraph(graphType):
    g = graphType()
    for name in ('Boston', 'Providence', 'New York', 'Chicago',
                 'Denver', 'Phoenix', 'Los Angeles'):
        g.addNode(Node(name))
    g.addEdge(Edge(g.getNode('Boston'), g.getNode('Providence')))
    g.addEdge(Edge(g.getNode('Boston'), g.getNode('New York')))
    g.addEdge(Edge(g.getNode('Providence'), g.getNode('Boston')))
    g.addEdge(Edge(g.getNode('Providence'), g.getNode('New York')))
    g.addEdge(Edge(g.getNode('New York'), g.getNode('Chicago')))
    g.addEdge(Edge(g.getNode('Chicago'), g.getNode('Denver')))
    g.addEdge(Edge(g.getNode('Chicago'), g.getNode('Phoenix')))
    g.addEdge(Edge(g.getNode('Denver'), g.getNode('Phoenix')))
    g.addEdge(Edge(g.getNode('Denver'), g.getNode('New York')))
    g.addEdge(Edge(g.getNode('Los Angeles'), g.getNode('Boston')))
    return g

def printPath(path):
    """Assumes path is a list of nodes"""
    result = ''
    for i in range(len(path)):
        result = result + str(path[i])
        if i != len(path) - 1:
            result = result + '->'
    return result
1
2
3
4
def nextSteps(graph, node, path):
    return ...  # your code here

Python runs in your browser
⌘/Ctrl + Enter runs
?
returns a list
?
an empty path keeps every child
?
skips a node already on the path
?
a node with no children gives nothing
←Previous Coding a Graph in Python: Node, Edge, Digraph and GraphNext Breadth-First Search: A Queue of Paths, Fewest Hops First →