1

我编写了一个代码来遍历无向非加权图。现在我希望这段代码适用于加权图,其中权重将确定节点之间的距离,我的代码将给出起始节点和结束节点之间的最短路径。我无法获得代码的逻辑。有人可以帮帮我吗。

graph = {'A': ['B', 'C', 'E'],
         'B': ['A','D', 'E'],
         'C': ['A', 'F', 'G'],
         'D': ['B'],
         'E': ['A', 'B','D'],
         'F': ['C'],
         'G': ['C']}
def undirected_graph(graph,start,stop):
    visited = []
    queue = [start]
    if start == stop:
        print("Woah we ended before even starting!")
    else:
       while queue:
        path = queue.pop(0)
        node = path[-1]
        if node not in visited:
            visited.append(node)
            neighbours = graph[node]
            for neighbour in neighbours:
                new_list = list(path)
                new_list.append(neighbour)
                queue.append(new_list)
                if neighbour == stop:
                    print("We reached the end")
                    return new_list
undirected_graph(graph,'A','G')
4

2 回答 2

0

networkx模块允许您创建图形并找到最短路径(Dijkstra 方法)。它与 Anaconda 发行版一起安装,否则使用pip install.

这是一个例子:

import networkx as nx
import pandas as pd

data = pd.read_excel('network.xlsx') # Some Graph
data

输出:

    Origin  Destination Distance
0   A       B           10
1   A       C           20
2   A       D           15
3   B       D           10
4   B       E           5
5   C       F           20
6   C       G           20
7   C       D           15
8   D       G           20
df = nx.from_pandas_edgelist(data, source='Origin', target='Destination', edge_attr=True)
nx.dijkstra_path(df, source='E', target='F', weight='Distance')

输出:

['E', 'B', 'D', 'C', 'F']

networkx模块提供更多:https ://networkx.github.io/documentation/stable/tutorial.html

例如,您可以绘制网络:

nx.draw_networkx(df, with_labels=True)

在此处输入图像描述

于 2019-09-05T18:29:15.310 回答
0

您正在寻找 Dijkstra 的最短路径算法。巧合的是,就在本周,我用 Python 实现了这个。实现有点重(因为我的目标是展示如何使用unittest执行单元测试),但它仍然有效。Dijkstra 的算法适用于有图,但您可以通过为每个无向边创建A -> B和有向边将无向图转换为有向图,就像您所做的那样。B -> AA -- B

from collections import defaultdict
from itertools import product, chain


class DijkstraNegativeWeightException(Exception):
    pass


class DijkstraDisconnectedGraphException(Exception):
    pass


class Dijkstra:

    def __init__(self, graph_data, source):
        self._graph = defaultdict(dict, graph_data)
        self._check_edge_weights()
        self.reset_source(source)
        self._solved = False

    @property
    def edges(self):
        return [(i, j) for i in self._graph for j in self._graph[i]]

    @property
    def nodes(self):
        return list(set(chain(*self.edges)))

    def _check_source_in_nodes(self):
        msg = 'Source node \'{}\' not in graph.'
        if self._source not in self.nodes:
            raise ValueError(msg.format(self._source))

    def _check_edge_weights(self):
        msg = 'Graph has negative weights, but weights must be non-negative.'
        if any(self._graph[i][j] < 0 for (i, j) in self.edges):
            raise DijkstraNegativeWeightException(msg)

    def reset_source(self, source):
        self._source = source
        self._check_source_in_nodes()
        self._solution_x = []
        self._solution_z = {source: 0}
        self._visited = set([source])
        self._unvisited = set()
        for key, val in self._graph.items():
            self._unvisited.add(key)
            self._unvisited.update(val.keys())
        self._unvisited.difference_update(self._visited)
        self._solved = False

    def run(self):
        weight_candidates = self._graph[self._source].copy()
        node_candidates = dict(product(weight_candidates.keys(),
                                       (self._source,)))
        while node_candidates:
            j = min(weight_candidates, key=weight_candidates.get)
            weight_best, i = weight_candidates.pop(j), node_candidates.pop(j)
            for k in self._graph[j].keys() & self._unvisited:
                weight_next = self._graph[j][k]
                if (k not in node_candidates
                        or weight_candidates[k] > weight_best + weight_next):
                    weight_candidates[k] = weight_best + weight_next
                    node_candidates[k] = j
            self._solution_x.append((i, j))
            self._solution_z[j] = weight_best
            self._visited |= {j}
            self._unvisited -= {j}
        self._solved = True

    def path_to(self, target):
        if self._source in self._visited and target in self._unvisited:
            msg = 'No path from {} to {}; graph is disconnected.'
            msg = msg.format(self._visited, self._unvisited)
            raise DijkstraDisconnectedGraphException(msg)
        solution = self._solution_x.copy()
        path = []
        while solution:
            i, j = solution.pop()
            if j == target:
                path.append((i, j))
                break
        while solution:
            i_prev, _, i, j = *path[-1], *solution.pop()
            if j == i_prev:
                path.append((i, j))
                if i == self._source:
                    break
        return list(reversed(path)), self._solution_z[target]

    def visualize(self, source=None, target=None):
        import networkx as nx
        import matplotlib.pyplot as plt
        if (source is not None and source != self._source):
            self.reset_source(source)
        if not self._solved:
            self.run()
        if target is not None:
            path, _ = self.path_to(target=target)
        else:
            path = self._solution_x
        edgelist = self.edges
        nodelist = self.nodes
        nxgraph = nx.DiGraph()
        nxgraph.add_edges_from(edgelist)
        weights = {(i, j): self._graph[i][j] for (i, j) in edgelist}
        found = list(chain(*path))
        ncolors = ['springgreen' if node in found else 'lightcoral'
                   for node in nodelist]
        ecolors = ['dodgerblue' if edge in path else 'black'
                   for edge in edgelist]
        sizes = [3 if edge in path else 1 for edge in edgelist]
        pos = nx.kamada_kawai_layout(nxgraph)
        nx.draw_networkx(nxgraph, pos=pos,
                         nodelist=nodelist, node_color=ncolors,
                         edgelist=edgelist, edge_color=ecolors, width=sizes)
        nx.draw_networkx_edge_labels(nxgraph, pos=pos, edge_labels=weights)
        plt.axis('equal')
        plt.show()

对于您的图表(添加了权重),

graph_data = {
    "A": {"B": 1, "C": 1, "E": 1},
    "B": {"A": 1, "D": 1, "E": 1},
    "C": {"A": 1, "F": 1, "G": 1},
    "D": {"B": 1},
    "E": {"A": 1, "B": 1,"D": 1},
    "F": {"C": 1},
    "G": {"C": 1}
}
algo = Dijkstra(graph_data, source='A')
algo.run() # creates a shortest-path tree (SPT) to all reachable nodes
x, z = algo.path_to('G')
print(x)
print(z)
algo.visualize(source='A', target='G')

输出(遍历的边和这些边的组合权重)。

[('A', 'C'), ('C', 'G')]
2

可视化对于无向图来说看起来很粗糙,但它仍然为您提供了解决方案的要点。

在此处输入图像描述

于 2019-09-05T18:43:55.317 回答