Пожалуйста, найдите невидимую ошибку в моем коде в упражнении по планированию маршрута

#python #python-3.x #graph

#python #python-3.x #График

Вопрос:

Я пытаюсь решить это упражнение:

Как часть планировщика маршрутов, метод route_exists используется в качестве быстрого фильтра, если пункт назначения достижим, прежде чем использовать более трудоемкие процедуры для поиска оптимального маршрута. Дороги на карте растрируются и создают матрицу логических значений — True, если дорога присутствует, или False, если ее нет. Дороги в матрице соединяются только в том случае, если дорога сразу слева, справа, ниже или выше нее. Завершите метод route_exists, чтобы он возвращал True, если пункт назначения достижим, или False, если это не так. Параметры from_row и from_column являются начальной строкой и столбцом в map_matrix. to_row и to_column являются строкой и столбцом назначения в map_matrix. Параметр map_matrix — это вышеупомянутая матрица, созданная на основе карты. Например, следующий код должен возвращать True, поскольку пункт назначения достижим:

 map_matrix = [
    [True, False, False],
    [True, True, False],
    [False, True, True]
];

route_exists(0, 0, 2, 2, map_matrix)
  

Мое решение с рекурсией:

 def route_exists(from_row, from_column, to_row, to_column, map_matrix):
    if route_exists2(from_row, from_column, to_row, to_column, map_matrix):
        return True
    else:
        return False
def route_exists2(from_row, from_column, to_row, to_column, map_matrix):
    if (from_row<0 or from_row>=len(map_matrix) or from_column<0 or from_column>=len(map_matrix[0])):
        return False
    if map_matrix[from_row][from_column]:
        map_matrix[from_row][from_column]=False #traversed
        if (from_row == to_row and from_column ==to_column):
            return True
        return (route_exists2(from_row-1, from_column, to_row, to_column, map_matrix) or
                route_exists2(from_row, from_column-1, to_row, to_column, map_matrix) or
                route_exists2(from_row, from_column 1, to_row, to_column, map_matrix) or
                route_exists2(from_row 1, from_column, to_row, to_column, map_matrix))
        
if __name__ == '__main__':
    map_matrix = [
        [True, False, False],
        [True, True, False],
        [False, True, True]
    ];

    print(route_exists(0, 0, 2, 2, map_matrix))
  

Я получаю только 50% в 4 тестовых примерах этого упражнения с логическими ошибками, и я не могу воссоздать ошибку из тестовых примеров.

Ответ №1:

Окончательное решение, о котором упоминал @Frank Yellin.

 def route_exists(from_row, from_column, to_row, to_column, map_matrix):
    visited = [[False for i in range(len(map_matrix[0]))] for j in range(len(map_matrix))]
    
    def route_exists2(from_row, from_column, to_row, to_column, map_matrix):
        if (from_row<0 or from_row>=len(map_matrix) or from_column<0 or from_column>=len(map_matrix[0]) or visited[from_row][from_column]==True):
            return False
        if map_matrix[from_row][from_column]:
            visited[from_row][from_column]=True
            #map_matrix[from_row][from_column]=False #traversed
            if (from_row == to_row and from_column ==to_column):
                return True
            return (route_exists2(from_row-1, from_column, to_row, to_column, map_matrix) or
                    route_exists2(from_row, from_column-1, to_row, to_column, map_matrix) or
                    route_exists2(from_row, from_column 1, to_row, to_column, map_matrix) or
                    route_exists2(from_row 1, from_column, to_row, to_column, map_matrix))

    
    if route_exists2(from_row, from_column, to_row, to_column, map_matrix):
        return True
    else:
        return False
    
    
if __name__ == '__main__':
    map_matrix = [
        [True, False, False],
        [True, True, False],
        [False, True, True]
    ];
    

    print(route_exists(0, 0, 2, 2, map_matrix))
  

Результат 4/4!

Комментарии:

1. Приятно! Мое первоначальное решение состояло в том, чтобы добавить следующий комментарий. В общем, изменение структуры данных, которую вы передаете, — плохая идея. Вы должны рассматривать все поступающие данные как доступные только для чтения, если не знаете, что их безопасно изменять. Вам было бы лучше передать список / набор / словарь просмотренных индексов в качестве дополнительного аргумента и написать свой код так, чтобы они больше не посещались.

Ответ №2:

Вам нужно изменить конец на:

 result = (rout_exists2..........)
map_matrix[from_row][from_column] = True
return result
  

Когда вы выполнили рекурсивный вызов, а затем вернулись к вызывающему абоненту, вам нужно отменить все изменения, которые вы внесли в состояние.

===== Расширяю свой ответ ======

Представьте внешний вызов route_exists2() . Он хочет выполнить четыре рекурсивных вызова route_exists2() , и матрица, которую он хочет передать каждому из этих четырех рекурсивных вызовов, является полученной матрицей с изменением одной ячейки. Но каждый из этих четырех рекурсивных вызовов может дополнительно модифицировать матрицу, и эти изменения никогда не отменяются.

Комментарии:

1. Спасибо, что это решает проблему. Я изменил структуру с помощью списка посещенных. Я опубликую ответ.

Ответ №3:

Один из возможных подходов — сопоставить все возможные допустимые пункты назначения с учетом начальной точки, а затем проверить, предусмотрен ли желаемый пункт назначения. Я предполагаю, что это то, чего вы пытаетесь достичь в своем рекурсивном вызове, пытаясь разделить конец вашего route_exists() в нескольких вызовах route_exists() . Но проблема, как указал Фрэнк Йеллин, заключается в том, что, когда первый рекурсивный вызов полностью разрешен, вы устанавливаете для всех дорог этого пути значение False, тем самым избегая других возможных путей использования этих дорог. Я бы предпочел попытаться сохранить последние новые маршруты и взаимодействовать с ними.

 def route_exists(start_x, start_y, end_x, end_y, map_matrix):
    possible_routes = [[[start_x, start_y]]]
        # each route is a list of [x, y] points indicating all the route roads  
    added_routes = 0
    
    while True:
        routes_count = len(possible_routes)
        for route in possible_routes[-added_routes:]:
            # check only the active new rotes and their possible roads
            for x, y in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
                road_x = route[-1][0]   x
                road_y = route[-1][1]   y
                    # the possible road at the route end
                try:
                    if map_matrix[road_x][road_y]: # the road exists
                        if [road_x, road_y] not in route: # not going backwards
                            new_route = route   [[road_x, road_y]]
                            if new_route not in possible_routes:
                                possible_routes.append(new_route)
                except:
                    pass

        added_routes = len(possible_routes) - routes_count
        if added_routes == 0:
            break

    destinations = [r[-1] for r in possible_routes]
    if [end_x, end_y] in destinations:
        return True
    else:
        return False
  

этот метод проверяет и сохраняет все возможные дороги, и я предполагаю, что это решит проблему, но он будет потреблять память по мере увеличения map_matrix, поэтому я рекомендую вам изменить его в соответствии с вашими потребностями.

Комментарии:

1. ваш скрипт набрал 1/4 балла в тестовых примерах, но я действительно ценю ваше время!