Пример #1
0
    def buildGraph(mapEntries):
        g = Digraph()
        nodelist = []

        #createing nodelist and adding nodes
        for eachEntry in mapEntries:
            eachEntrySource = eachEntry[0]
            eachEntryDest = eachEntry[1]
            if eachEntrySource not in nodelist:  #making sure the node is unique
                nodelist.append(eachEntrySource)
                g.add_node(Node(eachEntrySource))
            if eachEntryDest not in nodelist:
                nodelist.append(eachEntryDest)
                g.add_node(Node(eachEntryDest))

        #creating edges
        for eachEntry in mapEntries:
            src = Node(eachEntry[0])  #eachEntrySource Node
            dest = Node(eachEntry[1])  #"eachEntryDest"
            tD = eachEntry[2]  #eachEntryTotalDistance
            oD = eachEntry[3]  #eachEntryOutdoorDistance
            g.add_edge(WeightedEdge(src, dest, tD,
                                    oD))  #Adding the weighted edge kind

        return g
Пример #2
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    g = Digraph()
    with open(map_filename) as f:
        data = f.read().strip()
    dataList = data.split('\n')
    for mapEdge in dataList:
        edgeList = mapEdge.split(' ')  # from to TD, DO
        fromN = Node(edgeList[0])
        toN = Node(edgeList[1])
        if not g.has_node(fromN):
            g.add_node(fromN)
        if not g.has_node(toN):
            g.add_node(toN)
        g.add_edge(WeightedEdge(fromN, toN, edgeList[2], edgeList[3]))
    return g
Пример #3
0
 def jaccards_coefficient(self, source, target):
     nodes1 = self.database.one_to_many_nodes(source)
     nodes2 = self.database.one_to_many_nodes(target)
     n1 = set([Node(n).id for n in nodes1])
     n2 = set([Node(n).id for n in nodes2])
     score = len(n1.intersection(n2)) / len(n1.union(n2))
     return score
Пример #4
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    print("Loading map from file...")
    g = Digraph()
    with open(map_filename, "r") as file:
        for line in file:
            (src, dst, tot_dist, outdoor_dist) = line.split(' ')
            tot_dist = int(tot_dist)
            outdoor_dist = int(outdoor_dist)
            if not g.has_node(Node(src)):
                g.add_node(Node(src))
            if not g.has_node(Node(dst)):
                g.add_node(Node(dst))
            g.add_edge(WeightedEdge(src, dst, tot_dist, outdoor_dist))
    return g
Пример #5
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """

    # TODO
    # print("Loading map from file...")
    file = open(map_filename, 'r')  # open the file
    g = Digraph()
    for line in file:  # read each line of the file
        line = line.strip('\n')  # remove the \n character
        line = line.split(' ')
        for i in range(0, 2):
            nod = Node(line[i])
            if not g.has_node(nod):
                g.add_node(nod)
        wei_edge = WeightedEdge(Node(line[0]), Node(line[1]), int(line[2]),
                                int(line[3]))
        g.add_edge(wei_edge)
    file.close()
    return g
Пример #6
0
def test_shortest_path_dijkstra_2():
    g = Graph()
    a = Node('A')
    b = Node('B')
    g.node_list.append(a)
    g.node_list.append(b)
    assert g.shortest_path_dijkstra(a, b) is None
Пример #7
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    print("Loading map from file...")
    inFile = open(map_filename, 'r')
    digraph = Digraph()
    for line in inFile:
        mapEntry = line.split()  #mapEntry(list)
        src = Node(mapEntry[0])
        dest = Node(mapEntry[1])
        total_distance = int(mapEntry[2])
        outdoor_distance = int(mapEntry[3])
        edge = WeightedEdge(src, dest, total_distance, outdoor_distance)

        if not digraph.has_node(src):
            digraph.add_node(src)
        if not digraph.has_node(dest):
            digraph.add_node(dest)
        digraph.add_edge(edge)
    return digraph
Пример #8
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    print("Loading map from file...")
    # MY_CODE
    map_graph = Digraph()
    with open(map_filename, 'r') as f:
        for line in f:
            src, dest, total_dist, outdoor_dist = line.split(' ')
            src = Node(src)
            dest = Node(dest)
            if not map_graph.has_node(src):
                map_graph.add_node(src)
            if not map_graph.has_node(dest):
                map_graph.add_node(dest)
            edge = WeightedEdge(src, dest, int(total_dist), int(outdoor_dist))
            map_graph.add_edge(edge)
    return map_graph
def graph():
    graph = Graph()
    graph.adjacency_list.append(Node('a'))
    graph.adjacency_list.append(Node('b'))
    graph.addEdge('a', 'b', 1)
    graph.addEdge('b', 'a', 2)
    return graph
Пример #10
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    g = Digraph()  # Create a digraph object
    print("Loading map from file...")
    with open(map_filename, "r") as f:
        for passage in f:
            # For each entry, store four info
            From, To, TotalD, OutD = passage.split()
            node_src, node_dest = Node(From), Node(To)
            if not g.has_node(node_src):
                g.add_node(node_src)
            if not g.has_node(node_dest):
                g.add_node(node_dest)

            g.add_edge(
                WeightedEdge(node_src, node_dest, int(TotalD), int(OutD)))
    return g
Пример #11
0
def get_best_path(digraph, start, end, path, max_dist_outdoors, best_dist, best_path):
    """
    Finds the shortest path between buildings subject to constraints.

    Parameters:
        digraph: Digraph instance
            The graph on which to carry out the search
        start: string
            Building number at which to start
        end: string
            Building number at which to end
        path: list composed of [[list of strings], int, int]
            Represents the current path of nodes being traversed. Contains
            a list of node names, total distance traveled, and total
            distance outdoors.
        max_dist_outdoors: int
            Maximum distance spent outdoors on a path
        best_dist: int
            The smallest distance between the original start and end node
            for the initial problem that you are trying to solve
        best_path: list of strings
            The shortest path found so far between the original start
            and end node.

    Returns:
        A tuple with the shortest-path from start to end, represented by
        a list of building numbers (in strings), [n_1, n_2, ..., n_k],
        where there exists an edge from n_i to n_(i+1) in digraph,
        for all 1 <= i < k and the distance of that path.

        If there exists no path that satisfies max_total_dist and
        max_dist_outdoors constraints, then return None.
    """
    start_node = Node(start)  # 转换为Node对象
    end_node = Node(end)      # 转换为Node对象
    if not digraph.has_node(start_node) or not digraph.has_node(end_node):
        raise ValueError('Node not exist')
    elif start == end:        # 递归到end时,直接返回当前路径及其总长度
        return path[0], path[1]
    else:
        for edge in digraph.edges[start_node]:
            # 加入下一个节点(当前起点的邻接点),构造出一个新路径,作为path参数进行递归
            next_node = edge.get_destination().get_name()
            next_path_nodes = path[0] + [next_node]    # 新路径经过的节点列表
            next_path_total_dist = path[1] + edge.get_total_distance()         # 新路径的总长度
            next_path_outdoor_dist = path[2] + edge.get_outdoor_distance()     # 新路径的室外长度
            next_path = [next_path_nodes, next_path_total_dist, next_path_outdoor_dist]  # 新的path参数

            if (next_node not in path[0]) and (next_path[2] <= max_dist_outdoors) and (next_path[1] < best_dist):
                # 递归
                new_best_path = get_best_path(digraph, next_node, end, next_path, max_dist_outdoors, best_dist, best_path)
                # 更新
                if new_best_path is not None and new_best_path[1] < best_dist:
                    best_dist = new_best_path[1]  # 新的最短路径的长度
                    best_path = new_best_path[0]  # 新的最短路径的节点列表

        if best_path: # 列表非空,返回元组
            return best_path, best_dist
        else:         # 列表为空,返回None
            return None
Пример #12
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    print("Loading map from file...")
    graph = Digraph()  # 创建空图
    with open(map_filename) as file:
        for line in file:
            elements = line.split()  # 按空格分割成list
            src = Node(elements[0])
            dest = Node(elements[1])
            total_distance = int(elements[2])    # 数字类型
            outdoor_distance = int(elements[3])  # 数字类型

            if not graph.has_node(src):
                graph.add_node(src)
            if not graph.has_node(dest):
                graph.add_node(dest)
            graph.add_edge(WeightedEdge(src, dest, total_distance, outdoor_distance))

    return graph
Пример #13
0
def simulated_annealing_full(graph, start, goal, rand,
                             schedule=exp_schedule()):
    """ This version returns all the states encountered in reaching 
    the goal state."""
    states = []
    start_node = Node(start, None)
    current = Node(start, None)

    for t in range(sys.maxsize):
        states.append(current.name)
        T = schedule(t)
        if T == 0:
            path = []
            while current != start_node:
                path.append(current.name + ': ' + str(current.f))
                current = current.parent
            path.append(start_node.name + ': ' + str(start_node.f))
            # Return reversed path
            return path[::-1]
            #return states
        neighbors = graph.get(current.name)
        if not neighbors:
            return current.name
        next_choice = Node(choose(list(neighbors), rand), current)

        # Calculates path cost with realistic components
        current.f = components.componentAdjustments(
            rand, heuristicFunction(str(current.name), goal))
        next_choice.f = components.componentAdjustments(
            rand, heuristicFunction(str(next_choice.name), goal))

        # calcualtes delta e with the path costs
        delta_e = current.f - next_choice.f
        if delta_e > 0 or probability(np.exp(delta_e / T)):
            current = next_choice
Пример #14
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """
    print("Loading map from file...")
    mit_map = Digraph()
    with open(map_filename, "r") as file:
        for line in file:
            content = line.split()
            src = Node(content[0])
            dest = Node(content[1])
            edge = WeightedEdge(src, dest, int(content[2]), int(content[3]))
            if not mit_map.has_node(src):
                mit_map.add_node(src)
            if not mit_map.has_node(dest):
                mit_map.add_node(dest)
            mit_map.add_edge(edge)
    return mit_map
Пример #15
0
def test_add_edge():
    _graph = Graph()
    _node1 = Node(4)
    _node2 = Node(5)
    _graph.add_edges(_node1, _node2, 1)
    assert _graph.graph == {'n0': {'n1': 1},
                            'n1': {'n0': 1}}
Пример #16
0
def directed_dfs(digraph, start, end, max_total_dist, max_dist_outdoors):
    """
    Finds the shortest path from start to end using a directed depth-first
    search. The total distance traveled on the path must not
    exceed max_total_dist, and the distance spent outdoors on this path must
    not exceed max_dist_outdoors.

    Parameters:
        digraph: Digraph instance
            The graph on which to carry out the search
        start: string
            Building number at which to start
        end: string
            Building number at which to end
        max_total_dist: int
            Maximum total distance on a path
        max_dist_outdoors: int
            Maximum distance spent outdoors on a path

    Returns:
        The shortest-path from start to end, represented by
        a list of building numbers (in strings), [n_1, n_2, ..., n_k],
        where there exists an edge from n_i to n_(i+1) in digraph,
        for all 1 <= i < k

        If there exists no path that satisfies max_total_dist and
        max_dist_outdoors constraints, then raises a ValueError.
    """
    # MY_CODE
    ret = get_best_path(digraph, Node(start), Node(end), [[start], 0, 0],
                        max_dist_outdoors, max_total_dist, None)
    if ret[0] is None:
        raise ValueError("Problem shouldn't be impossible!")
    else:
        return ret[0]
Пример #17
0
def test_has_node():
    _graph = Graph()
    _node1 = Node(4)
    _node2 = Node(5)
    _graph.add_node(_node1)
    assert _graph.had_node(_node1) == True
    assert _graph.had_node(_node2) == False
Пример #18
0
    def _construct_graph(
            customers: Mapping[int, CustomerDemand], review_demands: Dict[int,
                                                                          int],
            num_of_products: int) -> Tuple[FlowGraph, Node, Node, dict]:
        source = Node("source")
        sink = Node("sink")
        graph = FlowGraph()

        product_nodes = {}
        for product in range(1, num_of_products + 1):
            product_node = Node("P" + str(product))
            product_nodes[product] = product_node
            graph.create_edge(product_node, sink, review_demands[product], inf)

        assignment_edges = {}
        for customer in customers.values():
            customer_node = Node("C" + str(customer.i))
            graph.create_edge(source, customer_node, customer.low,
                              customer.upper)
            for product in customer.products:
                edge = graph.create_edge(customer_node, product_nodes[product],
                                         0, 1)
                assignment_edges[(customer.i, product)] = edge

        return graph, source, sink, assignment_edges
Пример #19
0
def test_find_all_paths():
    """
    you should test with graphs that have 0, 1, 3 paths
    """
    g = Graph()
    node_1 = Node({'A': ['B', 'C']})
    g.add(node_1)
    node_2 = Node({'B': ['C', 'D']})
    g.add(node_2)
    node_3 = Node({'C': ['D']})
    g.add(node_3)
    node_4 = Node({'D': ['C']})
    g.add(node_4)
    node_5 = Node({'E': ['C']})
    g.add(node_5)

    # zero path between node_1 and node_5
    paths_0 = g.find_all_paths(node_1, node_5)
    assert len(paths_0) == 0
    # only one path between node_5 and node_4
    paths_1 = g.find_all_paths(node_5, node_4)
    assert len(paths_1) == 1
    assert [node.name
            for node in paths_1[0]] == [node_5.name, node_3.name, node_4.name]
    # three paths between node_1 and node_3, verify all the three paths are returned
    paths_3 = g.find_all_paths(node_1, node_3)
    assert len(paths_3) == 3
    for path in paths_3:
        assert [ node.name for node in path ] == [ node_1.name, node_2.name, node_3.name ] or \
            [ node.name for node in path ] == [ node_1.name, node_2.name, node_4.name, node_3.name ] or \
            [ node.name for node in path ] == [ node_1.name, node_3.name ]
Пример #20
0
def test_edge_init():
    e = Edge(Node(1), Node(2))
    assert e is not None
    assert e.n1 is not None
    assert e.n1.value == 1
    assert e.n2 is not None
    assert e.n2.value == 2
Пример #21
0
def test_find_shortest_path():
    """
    you should test with graphs that have 0, 1, 3 paths
    """
    g = Graph()
    node_1 = Node({'A': ['B', 'C']})
    g.add(node_1)
    node_2 = Node({'B': ['C', 'D']})
    g.add(node_2)
    node_3 = Node({'C': ['D']})
    g.add(node_3)
    node_4 = Node({'D': ['C']})
    g.add(node_4)
    node_5 = Node({'E': ['C']})
    g.add(node_5)

    # zero path between node_1 and node_5
    path_0 = g.find_shortest_path(node_1, node_5)
    assert path_0 == None
    # only one path between node_5 and node_4
    path_1 = g.find_shortest_path(node_5, node_4)
    assert [node.name
            for node in path_1] == [node_5.name, node_3.name, node_4.name]
    # three paths between node_1 and node_3, verify the shortest one is returned
    path_3 = g.find_shortest_path(node_1, node_3)
    assert [node.name for node in path_3] == [node_1.name, node_3.name]
Пример #22
0
 def common_neighbors(self, source, target):
     nodes1 = self.database.one_to_many_nodes(source)
     nodes2 = self.database.one_to_many_nodes(target)
     n1 = set([Node(n).id for n in nodes1])
     n2 = set([Node(n).id for n in nodes2])
     score = len(n1.intersection(n2))
     return score
Пример #23
0
def directed_dfs(digraph, start, end, max_total_dist, max_dist_outdoors):
    """
    Finds the shortest path from start to end using a directed depth-first
    search. The total distance traveled on the path must not
    exceed max_total_dist, and the distance spent outdoors on this path must
    not exceed max_dist_outdoors.

    Parameters:
        digraph: Digraph instance
            The graph on which to carry out the search
        start: string
            Building number at which to start
        end: string
            Building number at which to end
        max_total_dist: int
            Maximum total distance on a path
        max_dist_outdoors: int
            Maximum distance spent outdoors on a path

    Returns:
        The shortest-path from start to end, represented by
        a list of building numbers (in strings), [n_1, n_2, ..., n_k],
        where there exists an edge from n_i to n_(i+1) in digraph,
        for all 1 <= i < k

        If there exists no path that satisfies max_total_dist and
        max_dist_outdoors constraints, then raises a ValueError.
    """
    start=Node(start)
    end=Node(end)
    best_path=get_best_path(digraph,start,end,[],max_total_dist,max_dist_outdoors,None)
    if best_path==None:
        raise ValueError('NO best path exists')
    return [node.get_name() for node in best_path]
Пример #24
0
 def preferential_attachment(self, source, target):
     nodes1 = self.database.one_to_many_nodes(source)
     nodes2 = self.database.one_to_many_nodes(target)
     n1 = set([Node(n).id for n in nodes1])
     n2 = set([Node(n).id for n in nodes2])
     score = len(n1) * len(n2)
     return score
Пример #25
0
def load_map(mapFname):
    #TODO
    print "Loading map from file..."
    dataFile = open(mapFname, 'r') #open mit_map.txt in read-only mode, assign it to dataFile variable
    
    travel_map = WD() #create empty weighted directed graph
    
    node_dic = {}
    edge_list = []
    
    for line in dataFile:
        if len(line) == 0 or line[0] == '#': #skip null or comment lines
            continue
        src, dest, distance, outside_distance = line.split() #pull relevant data from line
        
        if src not in node_dic:
            node_dic[src] = Node(src)
        if dest not in node_dic:
            node_dic[dest] = Node(dest)
        
        edge_list.append((src, dest, distance, outside_distance))
    
    for node in node_dic.values():
        travel_map.addNode(node)    
    for edge in edge_list:
        start = node_dic[edge[0]] 
        end = node_dic[edge[1]]
        WEdge = WE(start, end, edge[2], edge[3])
        travel_map.addEdge(WEdge)
        
    dataFile.close()
        
    return travel_map
Пример #26
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """

    print("Loading map from file...")
    openfile = open(map_filename, 'r')
    gph = Digraph()
    for line in openfile:
        NewLine = line.strip('\n').split(" ")
        a, b, c, d = NewLine
        a, b = Node(a), Node(b)
        c, d = int(c), int(d)
        if a not in gph.nodes:
            gph.add_node(a)
        if b not in gph.nodes:
            gph.add_node(b)
        DirEdge = WeightedEdge(a, b, c, d)
        gph.add_edge(DirEdge)
    openfile.close()
    return gph
Пример #27
0
def load_map(map_filename):
    """
    Parses the map file and constructs a directed graph

    Parameters:
        map_filename : name of the map file

    Assumes:
        Each entry in the map file consists of the following four positive
        integers, separated by a blank space:
            From To TotalDistance DistanceOutdoors
        e.g.
            32 76 54 23
        This entry would become an edge from 32 to 76.

    Returns:
        a Digraph representing the map
    """

    #    print("Loading map from file...")
    inFile = open(map_filename, 'r')
    graph = Digraph()
    for line in inFile:
        linedata = line.split(' ')
        scr = Node(linedata[0])
        des = Node(linedata[1])
        graph.nodes.add(scr)
        graph.nodes.add(des)
        if not scr in graph.edges:
            graph.add_node(scr)
        if not des in graph.edges:
            graph.add_node(des)
        edge = WeightedEdge(scr, des, int(linedata[2]), int(linedata[3]))
        graph.add_edge(edge)
    return graph
Пример #28
0
    def create_graph(name, num_mid=200):
        '''
        Create a graph instance for use with Mnist.

        @type  name: str
        @param name:
            The name of the graph.
        @type  num_mid: int
        @param num_mid:
            The number of nodes in the middle hidden layer.
        '''
        # Create the net graph, first the nodes
        ins = [
            Node(node_type=NodeType.IN) for i in range(Mnist._IMG_SIZE_FLAT)
        ]
        mids = [Node() for i in range(int(num_mid))]
        outs = [Node(node_type=NodeType.OUT) for i in range(Mnist._N_CLASSES)]

        # Connect them up
        for r in ins:
            for n in mids:
                n.add_referee(r)
        for r in mids:
            for n in outs:
                n.add_referee(r)

        # Put them into the graph
        graph = Graph(name, ins, outs)
        for n in mids:
            graph.add_node(n)
        assert graph.is_connected()

        # And give it back
        return graph
Пример #29
0
def get_best_path(digraph, start, end, path, max_dist_outdoors, best_dist,
                  best_path):
    """
    Finds the shortest path between buildings subject to constraints.

    Parameters:
        digraph: Digraph instance
            The graph on which to carry out the search
        start: string
            Building number at which to start
        end: string
            Building number at which to end
        path: list composed of [[list of strings], int, int]
            Represents the current path of nodes being traversed. Contains
            a list of node names, total distance traveled, and total
            distance outdoors.
        max_dist_outdoors: int
            Maximum distance spent outdoors on a path
        best_dist: int
            The smallest distance between the original start and end node
            for the initial problem that you are trying to solve
        best_path: list of strings
            The shortest path found so far between the original start
            and end node.

    Returns:
        A tuple with the shortest-path from start to end, represented by
        a list of building numbers (in strings), [n_1, n_2, ..., n_k],
        where there exists an edge from n_i to n_(i+1) in digraph,
        for all 1 <= i < k and the distance of that path.

        If there exists no path that satisfies max_total_dist and
        max_dist_outdoors constraints, then return None.
    """
    # sanity checks
    start_node, end_node = Node(start), Node(end)
    if not digraph.has_node(start_node) or not digraph.has_node(end_node):
        raise ValueError('Start or end node do not exist in digraph')

    # base case: update best path, best dist
    elif start_node == end_node:
        best_path, best_dist = path[0], path[1]

    for edge in digraph.get_edges_for_node(
            start_node):  # for each outgoing edge
        current_node = edge.get_destination()  # get the dest node
        if current_node.get_name() not in path[0]:  # no loops
            current_path = path[0] + [current_node.get_name()
                                      ]  # add onto current path
            total_outdoor_dist = edge.get_outdoor_distance() + path[2]
            total_dist = edge.get_total_distance() + path[1]
            if total_outdoor_dist <= max_dist_outdoors and (
                    best_dist == None or total_dist <= best_dist):
                updatedPath = [current_path, total_dist, total_outdoor_dist]
                newPath = get_best_path(digraph, current_node, end,
                                        updatedPath, max_dist_outdoors,
                                        best_dist, best_path)
                if newPath != None: best_path, best_dist = newPath
    return (best_path, best_dist) if best_path != None else None
Пример #30
0
def get_best_path(digraph, start, end, path, max_dist_outdoors, best_dist,
                  best_path):
    """
    Finds the shortest path between buildings subject to constraints.

    Parameters:
        digraph: Digraph instance
            The graph on which to carry out the search
        start: string
            Building number at which to start
        end: string
            Building number at which to end
        path: list composed of [[list of strings], int, int]
            Represents the current path of nodes being traversed. Contains
            a list of node names, total distance traveled, and total
            distance outdoors.
        max_dist_outdoors: int
            Maximum distance spent outdoors on a path
        best_dist: int
            The smallest distance between the original start and end node
            for the initial problem that you are trying to solve
        best_path: list of strings
            The shortest path found so far between the original start
            and end node.

    Returns:
        A tuple with the shortest-path from start to end, represented by
        a list of building numbers (in strings), [n_1, n_2, ..., n_k],
        where there exists an edge from n_i to n_(i+1) in digraph,
        for all 1 <= i < k and the distance of that path.

        If there exists no path that satisfies max_total_dist and
        max_dist_outdoors constraints, then return None.
    """
        
    path[0] = path[0] + [start]
    if not (digraph.has_node(Node(start)) and digraph.has_node(Node(end))): 
        raise ValueError("Graph doesn't have the node")
    if start == end: 
        return (path[0], path[1]) 
    
    for edge in digraph.get_edges_for_node(Node(start)): 
        #避免回路
        if str(edge.get_destination()) not in path[0]: 
            #要符合室外距离之和小于max_dist_outdoors
            if edge.get_outdoor_distance()+path[2]<=max_dist_outdoors:
                #判断是否需要更新路径,即判断路径是否为空或者有更短的路径
                if best_path == None or path[1]+edge.get_total_distance()<best_dist: 
                    #更新总距离和室外距离
                    tem_path=[path[0].copy(), path[1]+edge.get_total_distance(), path[2]+edge.get_outdoor_distance()]
                    #对更新了总距离和室外距离的路径递归调用函数,注意返回值是元组
                    new_path,new_dist = get_best_path(digraph, str(edge.get_destination()), end, 
                                                      tem_path, max_dist_outdoors, best_dist, best_path) 
                    #如果找到了就更新最佳路径和最佳距离
                    if new_path != None:
                        best_path = new_path 
                        best_dist = new_dist

    return (best_path, best_dist)