CentraleSupélec
Département informatique
Plateau de Moulon
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
1CC2000 - Algorithmique et Complexité - TD02 Practice

TD02 - Paths and trees

Implementation in Python of the Dijkstra algorithm, the Prim algorithm and the Kruskal algorithm seen during the course and during the TD 2. A set of functions are defined and loaded during the execution of the first cell. They help to load data to test and to verify the produced solutions, etc.

Each function you need to complete is followed by tests to verify that the produced result is correct.

The graphs are represented as dictionaries and you can use the following Python functions:

  • nodes (graph): returns the list of vertices of graph.
  • neighbors (graph, x): returns the list of neighboring vertices of x in the graph.
  • distance (graph, x, y): returns the distance between the vertices x and y of the graph, or None if they are not neighbors.

Exercise plan :

  • Shortest Path ;
  • Minimum Spanning Tree : Prim algorithm ;

Optional :

  • Minimum Spanning Tree : Kruskal algorithm ;

The next cell allows the loading of the graph hameau seen in TD2 and displays it using the Python module NetworkX.

import numpy as np

# TO RUN
import zlib, base64
exec(zlib.decompress(base64.b64decode(b'eJy1V0tv4zYQPq9/xTQ9SGpUI4/tZteAD9vtbraXtij2ZhgGI41tIhIpUFRsNfD/afo3/Mc6fOjpJsilAmxSnJlvZsh5UGslc1BMpDTwvJBK2zcu9MS/CtQ7qe73wEoQ+2Y1Z7rIpM743bSozcyQi0z36NvYA08mKa79fLVRrNiGIoY8hh3yzVaXMIcvLCsxmk2AnrOzMzt+Usg0lwJYdnxiWnKFkAaVAAuBwB4wAQGlzHMkECSlwNTxH43l1AJkSCZJnpZQVsq+eTLJCA0oQBZGwZs3A70bsueRzx4PsJYKOHBhbN9gKKKDZRgt595u8+xJ1u9feBGLHy+jllQ/T9pteYbEQJCbxX4JhE9Ac6g74FNwGECcanB075t5+Lrd8CHubmjZD/kQ1pi0qJfEtBut10tjbX8d6RhH6J34N1XhMwgtSaGuFG3DxAVNJlnqQ2YTzWBwTiliAYks6n5UNBxw8kzav83KStEpi+aUhd377njde+eIWcvd+YjlyD+LRsuL3HiycbOBM04feJ9SXhYZq71buZ/EkLE72r7544GOTqZIQplU9hXTzclryz3Kmo/rNU8oO7o8oTivNM94ySjoMwaUs21Su0T5XUCBlYayOD4lfM1R0eaW3iBKIZ89QmKVlrGlubxqST6xLFoiqwwrdSJoMvSUNsjYT7TABW12bjPfJ2qpZXJ/fCJaymjNqE95YhgEo6LgZe3fH4xMPz6tGXnT02xhlKw2xAy/kk8CjccPSMsFM5ZRbbnLmEggIQSqOY7BUZOt5CU3ewJZICsqegKng0135YbdmVL2OCoSzQHP+oloKX5/h+FkUBbcRFIgAjgn51XIo2lVFKjCCM6DWXBu1pwwcUYvJd/LaBNXHIQNLeJZuLAl+7oANHXo8dChtsyBCiaN1mGiPON23/UePhWe3qs1dg4XQ7FO8ZSR6SINA6qZGoNhpcLsVfjfvQafjK9P4PuePiOnMO3E7HhLmyX201ub7o50O2VpujJWlas1deC2CkzvsS7DKGpDaP/fe2lIdZ9EZfRkp3s0W4BdmT31wFljqkq4j6F+jdMjkaaVk6dDpVGXHl0RW5V1bhOlpRl3qvjBONSx+b3olA8RFuFDXEUmtLv1RUgo0XKkj8I9ZRrDobwzDdvY7/FvUIcWKYYzqgrJ/VlkTbRrxsjbqeEm45adf4Us3UGvVZVsNVINEyuFXGxkllK5rqlyhLcxlIjp/CqC74FVUPB1h0CyqWI7w+Sru0nfeLj5ayplq5L/hfPLS98o7NvNxcWIkwya02+02mstLnIH7QX90o6neju/nP7UO0CKqF7n6R2LL3w9YlsY4JSNvKT9tbGzYlorfldR/SenAxdDPnv8ZqyaTrXqwROzcazfBy26k6Rb6LTcyh3lmmu4Ns9CG5U+mnxjpp6ow2HeeQljyZ1UXireezlbGbVLylFGKsbJ3c/7BO2dMgxsvkMqbRcynU9o5isTzMAV8b3P9BN7KHsak5rtt+fg7w+aOhV628DmbHsJcMx/oniQHE27b9jpHmC6XIrVvr0zP5jGRi110Mz+Lyc9bt3iDmrWGNpI1tTvIADuwFl7LCDXLXrdob9Y7E5M/0ZXIysBW/NlI5vLsY+/UfQ2V7lORf/gfpMCfei4wlDQ58/oYqaaI+l9h9ibDt1B6LJGd7acNobuG+XxydzZCqZYfvzbnFkpK8frPoDQBoo5Sne/aTO0UWVt6Pr56HslQ+Hso++DYXEtmy5m6dQqY3CT88ulyY2ex5Z9MtmyHKmMUTEPPgYz+v+Z/t/GEHyh8T3dVe2CIzbLH2i8pfGGxq80XtP4icZL+mYJfjGTq4Nfcngt4frgJ379yrNdeyTL+Jkm7w5+8mjZ33nNN17zu0bzwROcge+9uR+8cMP+9uAnTu1No8QLv+2jfW3ZrhtvGqOuPcr14TD5F+zfcK8=')))

hameau = load_graph(hameau)
display_graph(hameau)

Shortest Path

Complete the function dijkstra (graph, d, a). It takes as parameter a graph, the departure vertex d and the arrival vertex a. It returns a list containing the vertices in the visiting order of the shortest path between d and a. The code to retrieve the path from the parents list is given, you only need to focus and implement the shortest path algorithm in its classical form presented in previous lectures.

Test your code on the hameau example to go from A to E. You should obtain ['A', 'B', 'H', 'E']

def dijkstra(graph, d, a):
    parent = {}
    dist = {}

    # init
    for p in nodes(graph):
        parent[p], dist[p] = None, math.inf
    dist[d]=0

    frontier = [d]

    ############### TODO : complete code #####################



    # retrieve the path from the parent list
    if d == a:
        return []
    elif parent[a] == None:
        return None

    path = [a]
    current = a
    while parent[current] != None:
        current = parent[current]
        path.append(current)

    path.reverse();
    return path

# testing
path_A_E = dijkstra(hameau,'A','E')
assert path_A_E == ['A', 'B', 'H', 'E']

# displaying
edge_color = {e:"red" for e in edges(path_A_E)}
display_graph(hameau, edge_color=edge_color)

Minimum Spanning Tree : Prim algorithm

Complete the prim (graph, d) function. It takes as parameter a graph and the label of a departure vertex. It returns a list of edges corresponding to the minimum spanning tree of graph using the Prim algorithm. An edge is a pair/tuple (u, v).

def prim(graph, d):
    parent = {}
    dist = {}

    # init
    for p in nodes(graph):
        parent[p], dist[p] = None, math.inf
    dist[d]=0

    frontier = nodes(graph)

    ############### TODO : complete code #####################



    # retrieve the edges from the parent list
    edges = []
    for u in nodes(graph):
        if parent[u] != None:
            edges.append((parent[u], u))

    return edges

# testing
prim_edges = prim(hameau, 'H')
assert sum([distance(hameau, u, v) for u,v in prim_edges]) == 26 # the total weight

# displaying
edge_color = {e:"red" for e in prim_edges}
display_graph(hameau, edge_color=edge_color)

[Optional] Minimum Spanning Tree : Kruskal algorithm

Complete the kruskal (graph) function. It takes as parameter a graph and it returns a list of edges corresponding to the minimum spanning tree of graph using the Kruskal algorithm.

def kruskal(graph):

    # we sort edges depending on their weight 
    edges = sorted([(i, j) for i in nodes(graph) for j in neighbors(graph,i) if i < j], 
                   key = lambda e : distance(graph, e[0], e[1]))

    # structure for union-find
    forest = {}
    for i in graph:
        forest[i] = i

    mst = []

    ############### TODO : complete code #####################



    return mst

# testing
kruskal_edges = kruskal(hameau)
assert sum([distance(hameau, u, v) for u,v in kruskal_edges]) == 26 # the total weight

# displaying
edge_color = {e:"red" for e in kruskal_edges}
display_graph(hameau, edge_color=edge_color)