Хобрук: Ваш путь к мастерству в программировании

Максимальный суммарный путь в матрице с заданной начальной точкой

Я учусь решать аналогичные задачи динамического программирования, чтобы найти максимальную сумму путей в матрице.

Я основал свое обучение на этом алгоритме на веб-сайте ниже.

Источник: Максимальная сумма путей в матрице

Проблема, которую я пытаюсь решить, немного отличается от той, что описана на сайте.

Алгоритм с веб-сайта использует max() для обновления значений в матрице, чтобы найти максимальные значения для создания максимального пути.

Например, для массива:

sample = [[110, 111, 108, 1],
          [9, 8, 7, 2],
          [4, 5, 10, 300],
          [1, 2, 3, 4]]

Путь наилучшей суммы: 111 + 7 + 300 + 4 = 422

В приведенном выше примере алгоритм находит первый путь, определяя максимальное значение первой строки матрицы.

У меня вопрос, а что, если нужно указать начальную точку алгоритма. Значение h задается как первый элемент для запуска.

Например, учитывая приведенный выше образец массива, если h = 0, нам нужно начать с образца [0] [h], поэтому лучшим путем будет

110 (наша исходная точка) + 8 + 10 + 4 = 132

Как видите, путь может идти только вниз или рядом, поэтому, если мы начнем с h = 0, будут значения, которых мы не сможем достичь, например, 300.

Вот моя грязная попытка решить это в рамках сложности O (N * D),

# Find max path given h as a starting point
def find_max_path_w_start(mat, h):
    res = mat[0][0]
    M = len(mat[0])
    N = len((mat))

    for i in range(1, N):
        res = 0
        for j in range(M):
            # Compute the ajacent sum of the ajacent values from h
            if i == 1:
                # If h is starting area, then compute the sum, find the max
                if j == h:
                    # All possible
                    if (h > 0 and h < M - 1):
                        mat[1][h + 1] += mat[0][h]
                        mat[1][h] += mat[0][h]
                        mat[1][h - 1] += mat[0][h]
                        print(mat)
                    # Diagona Right not possible
                    elif (h > 0):
                        mat[1][h] += mat[0][h]
                        mat[1][h - 1] += mat[0][h]
                    # Diagonal left not possible
                    elif (h < M - 1):
                        mat[1][h] += mat[0][h]
                        mat[1][h + 1] += mat[0][h]
                # Ignore value that has been filled.
                elif j == h + 1 or j == h - 1 :
                    pass
                # Other elements that cannot reach, make it -1
                elif j > h + 1 or j < h - 1:
                    mat[i][j] = -1
            else:
                # Other elements that cannot reach, make it -1
                if j > h + 1 or j < h - 1:
                    mat[i][j] = -1
                else:
                    # When all paths are possible
                    if (j > 0 and j < M - 1):
                        mat[i][j] += max(mat[i - 1][j],
                                         max(mat[i - 1][j - 1],
                                             mat[i - 1][j + 1]))
                    # When diagonal right is not possible
                    elif (j > 0):
                        mat[i][j] += max(mat[i - 1][j],
                                         mat[i - 1][j - 1])
                    # When diagonal left is not possible
                    elif (j < M - 1):
                        mat[i][j] += max(mat[i - 1][j],
                                         mat[i - 1][j + 1])

            res = max(mat[i][j], res)

    return res

Мой подход состоит в том, чтобы хранить только достижимые значения, например, если мы начинаем с h = 0, поскольку мы начинаем с mat[0][h], мы можем вычислить только сумму текущего и минимального max(mat[1][h] и суммы текущего и смежного справа mat[1][h + 1]), для других значений я помечу его как -1, чтобы пометить его как недоступный.

Это не возвращает ожидаемую сумму в конце.

Моя логика неверна? Есть ли другие значения, которые мне нужно сохранить, чтобы завершить это?


Ответы:


1

Здесь легко построить восходящее решение. Начните думать о случае, когда есть только одна или две строки, и расширьте их, чтобы легко понять этот алгоритм.
Примечание: это изменяет исходную матрицу, а не создает новую. Если вам нужно запустить функцию несколько раз на одной и той же матрице, вам нужно будет создать копию матрицы, чтобы сделать то же самое.

def find_max_path_w_start(mat, h):
    res = mat[0][0]
    M = len(mat[0])
    N = len((mat))

    # build solution bottom up
    for i in range(N-2,-1,-1):
        for j in range(M):
            possible_values = [mat[i+1][j]]
            if j==0:
                possible_values.append(mat[i+1][j+1])
            elif j==M-1:
                possible_values.append(mat[i+1][j-1])
            else:
                possible_values.append(mat[i+1][j+1])
                possible_values.append(mat[i+1][j-1])
            mat[i][j] += max(possible_values)
    return mat[0][h]

sample = [[110, 111, 108, 1],
          [9, 8, 7, 2],
          [4, 5, 10, 300],
          [1, 2, 3, 4]]

print(find_max_path_w_start(sample, 0)) # prints 132
20.04.2021

2

Вы можете установить для всех элементов первой строки, кроме h, отрицательную бесконечность и вычислить ответ, как если бы не было ограничения на начальную точку.

Например, поместите этот фрагмент кода в начало вашего кода

for i in range(M):
    if i != h:
        mat[0][i] = -1e100
20.04.2021

3

Вот решение, которое работает аналогично вашему, однако оно вычисляет суммы путей только для значений матрицы, которые могли начаться с h.

def find_max_path_w_start(mat, h):
    M = len(mat[0])
    N = len((mat))

    for i in range(1, N):
        # `h - i` is the left hand side of a triangle with `h` as the top point.
        # `max(..., 0)` ensures that is is at least 0 and in the matrix.
        min_j = max(h - i, 0)

        # similar to above, but the right hand side of the triangle.
        max_j = min(h + i, M - 1)

        for j in range(min_j, max_j + 1):
            # min_k and max_k are the start and end indices of the points in the above
            # layer which could potentially lead to a correct solution.
            # Generally, you want to iterate from `j - 1` up to `j + 1`,
            # however if at the edge of the triangle, do not take points from outside the triangle:
            # this leads to the `h - i + 1` and `h + i - 1`.
            # The `0` and `M - 1` prevent values outside the matrix being sampled.
            min_k = max(j - 1, h - i + 1, 0)
            max_k = min(j + 1, h + i - 1, M - 1)

            # Find the max of the possible path totals
            mat[i][j] += max(mat[i - 1][k] for k in range(min_k, max_k + 1))
            
    # Only sample from items in the bottom row which could be paths from `h`
    return max(mat[-1][max(h - N, 0):min(h + N, M - 1) + 1])


sample = [[110, 111, 108, 1],
          [9, 8, 7, 2],
          [4, 5, 10, 300],
          [1, 2, 3, 4]]

print(find_max_path_w_start(sample, 0))
20.04.2021
Новые материалы

Настольный ПК как «одно кольцо, чтобы править всеми» домашних компьютеров
Вид после 9 месяцев использования С настольных компьютеров все началось, но в какой-то момент они стали «серверами», и мы все перешли на ноутбуки. В прошлом году я столкнулся с идеей настольных..

Расширенные методы безопасности для VueJS: реализация аутентификации без пароля
Руководство, которое поможет вам создавать безопасные приложения в долгосрочной перспективе Безопасность приложений часто упускается из виду в процессе разработки, потому что основная..

стройный-i18следующий
Представляем стройную оболочку для i18next. Эта библиотека, основанная на i18next, заключает экземпляр i18next в хранилище svelte и отслеживает события i18next, такие как languageChanged,..

Обзор 20 основных и современных методов работы с массивами в JavaScript
Вы знаете их всех? В этом коротком посте я покажу сводку методов, доступных в JavaScript для работы с массивами. Я надеюсь, что вы найдете это полезным! В конце поста вы найдете ссылку на..

Да, но я чувствую необходимость указать, что это или не единственные два.
Да, но я чувствую необходимость указать, что это или не единственные два. Обучение с подкреплением (в качестве примера) также является важным.

Получение стоковых обновлений с помощью Python
Для начинающего финансового аналитика Введение Описание: Этот проект Python создает скрипт для получения текущих обновлений акций с финансового веб-сайта Yahoo. Для этого проекта мы..

Это все, что вам нужно знать о Kotlin в 2022 году
Добро пожаловать! Kotlin — это язык программирования, популярность которого, кажется, растет, его действительно можно использовать для создания чего угодно, и если вы хотите узнать о Kotlin,..