Как реализовать функцию, которая выстраивает маршрут между городами

Задание такое: Реализуйте функцию build_itinerary(), которая выстраивает маршрут между городами. Есть список:`

tree = ['Moscow', [
    ['Smolensk'],
    ['Yaroslavl'],
    ['Voronezh', [
        ['Liski'],
        ['Boguchar'],
        ['Kursk', [
            ['Belgorod', [
                ['Borisovka'],
            ]],
            ['Kurchatov'],
        ]],
    ]],
    ['Ivanovo', [
        ['Kostroma'], ['Kineshma'],
    ]],
    ['Vladimir'],
    ['Tver', [
        ['Klin'], ['Dubna'], ['Rzhev'],
    ]],
]]

Мне удалось преобразовать список в надлежащий вид:

>>>def make_flat(tree, dictionary, parent=None):
    (node, branches) = tree
    children = []
    dictionary[node] = (parent, children)
    for branch in branches:
        if len(branch) == 1:
            children += branch
            dictionary[branch[0]] = (node, [])
        elif len(branch) > 1:
            name = make_flat(branch, dictionary, parent=node)
            children.append(name)
    return node
>>>flat = {}
>>>make_flat(tree, flat)
>>>flat
{'Moscow': (None,
  ['Smolensk', 'Yaroslavl', 'Voronezh', 'Ivanovo', 'Vladimir', 'Tver']),
 'Smolensk': ('Moscow', []),
 'Yaroslavl': ('Moscow', []),
 'Voronezh': ('Moscow', ['Liski', 'Boguchar', 'Kursk']),
 'Liski': ('Voronezh', []),
 'Boguchar': ('Voronezh', []),
 'Kursk': ('Voronezh', ['Belgorod', 'Kurchatov']),
 'Belgorod': ('Kursk', ['Borisovka']),
 'Borisovka': ('Belgorod', []),
 'Kurchatov': ('Kursk', []),
 'Ivanovo': ('Moscow', ['Kostroma', 'Kineshma']),
 'Kostroma': ('Ivanovo', []),
 'Kineshma': ('Ivanovo', []),
 'Vladimir': ('Moscow', []),
 'Tver': ('Moscow', ['Klin', 'Dubna', 'Rzhev']),
 'Klin': ('Tver', []),
 'Dubna': ('Tver', []),
 'Rzhev': ('Tver', [])}

Можете подсказать как мне обойти этот словарь и при этом сохранить маршрут? Должно получиться так:

build_itinerary(tree, 'Dubna', 'Kostroma')
['Dubna', 'Tver', 'Moscow', 'Ivanovo', 'Kostroma']

build_itinerary(tree,'Borisovka', 'Kurchatov')
['Borisovka', 'Belgorod', 'Kursk', 'Kurchatov']

build_itinerary(tree, 'Tver', 'Dubna')
['Tver', 'Dubna']

Ответы (1 шт):

Автор решения: MiniMax

Задача на графы. Для решения строим список смежностей (в нашем случае словарь), используя его ищем маршрут с помощью dfs.

def build_adj_dct(root, adj_dct):
    if len(root) == 1:
        return

    src_name, dest_lst = root
    src_to_dest_set = adj_dct.setdefault(src_name, set())
    for dest in dest_lst:
        src_to_dest_set.add(dest[0])
        dest_to_src_set = adj_dct.setdefault(dest[0], set())
        dest_to_src_set.add(src_name)
        build_adj_dct(dest, adj_dct)

def find_routes(adj_dct, src, dest):
    visited = set()
    def dfs(city, route=()):
        if city in visited:
            return

        if city == dest:
            yield route + (city,)
            return 

        visited.add(city)

        for dst in adj_dct[city]:
            yield from dfs(dst, route + (city,))

    return list(dfs(src))

tree = ['Moscow', [
    ['Smolensk'],
    ['Yaroslavl'],
    ['Voronezh', [
        ['Liski'],
        ['Boguchar'],
        ['Kursk', [
            ['Belgorod', [
                ['Borisovka'],
            ]],
            ['Kurchatov'],
        ]],
    ]],
    ['Ivanovo', [
        ['Kostroma'], ['Kineshma'],
    ]],
    ['Vladimir'],
    ['Tver', [
        ['Klin'], ['Dubna'], ['Rzhev'],
    ]],
]]    

adj_dct = {} 
build_adj_dct(tree, adj_dct)

tests = [
    ('Dubna', 'Kostroma', ('Dubna', 'Tver', 'Moscow', 'Ivanovo', 'Kostroma')),      
    ('Borisovka', 'Kurchatov', ('Borisovka', 'Belgorod', 'Kursk', 'Kurchatov')), 
    ('Tver', 'Dubna', ('Tver', 'Dubna')),           
]

for src, dst, right_ans in tests:
    ans = find_routes(adj_dct, src, dst)
    print(ans[0])
    assert ans[0] == right_ans, f"{ans[0]} != {right_ans}"
→ Ссылка