Учитывая, что кортежи в структуре данных являются ребрами, а значения в кортежах являются узлами графа, можно реорганизовать данные таким образом, чтобы упростить алгоритм:
graph = [edge for es in source.values() for edge in es]
Поскольку на графике могут быть петли, нам нужно отслеживать уже посещенные узлы. Имея это в виду рекурсивную функцию, находящую все пути от начального узла до конечного узла, передайте график в виде списка ребер от узла к узлу:
def find_path(start, end, edges, visited=None):
if visited is None:
visited = []
for n1, n2, in edges:
if n1 == start:
if n2 == end:
yield [n1, n2]
elif n2 not in visited:
for continuation in find_path(n2, end, edges, visited + [n1]):
yield [n1] + continuation
Все:
source = {
'node1': [('V1', 'R1')],
'node2': [('R1', 'R2'), ('R1', 'R3')],
'node3': [('R2', 'R4'), ('R2', 'R5'), ('R3', 'R4'), ('R3', 'R5')],
'node4': [('R4', 'Z1')],
'node5': [('R5', 'Z1')]
}
graph = [edge for es in source.values() for edge in es]
def find_path(start, end, edges, visited=None):
if visited is None:
visited = []
for n1, n2, in edges:
if n1 == start:
if n2 == end:
yield [n1, n2]
elif n2 not in visited:
for continuation in find_path(n2, end, edges, visited + [n1]):
yield [n1] + continuation
print(list(find_path('V1', 'Z1', graph)))
Вывод:
[['V1', 'R1', 'R2', 'R4', 'Z1'], ['V1', 'R1', 'R2', 'R5', 'Z1'], ['V1', 'R1', 'R3', 'R4', 'Z1'], ['V1', 'R1', 'R3', 'R5', 'Z1']]
Обратите внимание, что результат приводится к списку, поскольку функция является генератором, она выдает решения по одному за раз. Вызов list()
собирает все результаты в один вывод.