Решение задачи #6 на Python с Яндекс CodeRun — НОП с восстановлением ответа

Опубликовано: 01.12.2024, 01:09 | Автор: hdhAI

Вариант решения задачи на языке программирования Python с Яндекс CodeRun.
Категория: Алгоритмы.
Название задачи: НОП с восстановлением ответа.
Сложность: Средняя.
Статус решения: "Решено".

Условие задачи:
Даны две последовательности, требуется найти и вывести их наибольшую общую подпоследовательность.

Напомним:
Последовательность xx называется подпоследовательностью последовательности yy, если xx получается из 𝑦y удалением нескольких (возможно, нуля или всех) элементов.

Наибольшая общая подпоследовательность - последовательность наибольшей длины, которая является подпоследовательностью обеих последовательностей.
Формат ввода

В первой строке входных данных содержится число N – длина первой последовательности (1 ≤≤ N ≤≤ 1000). Во второй строке заданы члены первой последовательности (через пробел) – целые числа, не превосходящие 10000 по модулю.

В третьей строке записано число M – длина второй последовательности (1 ≤≤ M ≤≤ 1000). В четвертой строке задаются члены второй последовательности (через пробел) – целые числа, не превосходящие 10000 по модулю.
Формат вывода

Требуется вывести наибольшую общую подпоследовательность данных последовательностей, через пробел. Если таких подпоследовательностей несколько, то можно вывести любую.

Решение:


Python

import sys

def main():
    """
    Основная функция для нахождения наибольшей общей подпоследовательности (LCS).
    """
    # Считываем входные данные
    input = sys.stdin.read().splitlines()

    # Длина первой последовательности
    n = int(input[0])
    # Первая последовательность
    seq1 = list(map(int, input[1].split()))

    # Длина второй последовательности
    m = int(input[2])
    # Вторая последовательность
    seq2 = list(map(int, input[3].split()))

    # Инициализация таблицы для динамического программирования
    # dp[i][j] будет содержать длину LCS для seq1[0..i-1] и seq2[0..j-1]
    dp = [[0] * (m + 1) for _ in range(n + 1)]

    # Заполнение таблицы dp
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            if seq1[i - 1] == seq2[j - 1]:
                # Если элементы совпадают, увеличиваем длину подпоследовательности
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                # Иначе берём максимум из возможных вариантов
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

    # Восстановление наибольшей общей подпоследовательности
    lcs = []
    i, j = n, m
    while i > 0 and j > 0:
        if seq1[i - 1] == seq2[j - 1]:
            # Если символы совпадают, добавляем их в LCS
            lcs.append(seq1[i - 1])
            i -= 1
            j -= 1
        elif dp[i - 1][j] > dp[i][j - 1]:
            # Двигаемся в сторону большего значения в таблице dp
            i -= 1
        else:
            j -= 1

    # Порядок в lcs нужно развернуть, так как мы шли с конца
    lcs.reverse()

    # Выводим наибольшую общую подпоследовательность
    print(" ".join(map(str, lcs)))

if __name__ == "__main__":
    main()


Объяснение кода

Ввод данных:
Считываем размеры и элементы двух последовательностей.

Инициализация таблицы dp:
dp[i][j] хранит длину LCS для первых i элементов первой последовательности и первых j элементов второй последовательности.

Заполнение таблицы dp:
Если элементы совпадают, увеличиваем длину LCS.
Если элементы не совпадают, берем максимум между значениями слева и сверху.

Восстановление LCS:
Начинаем с последней ячейки таблицы dp и идем к началу, выбирая элементы, которые входят в LCS.

Вывод результата:
Порядок LCS восстанавливаем с помощью reverse(), так как элементы добавляются с конца к началу.

Источник решения: hdhai.com

Похожие статьи
Интересное