Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/f43c31b1335a2396013862d362c84845 to your computer and use it in GitHub Desktop.
Save anonymous/f43c31b1335a2396013862d362c84845 to your computer and use it in GitHub Desktop.
С приведенными выше способами

С приведенными выше способами



Дан массив из чисел: Требуется найти в этой последовательности строго возрастающую подпоследовательность наибольшей длины. Формально это выглядит следующим образом: В данной статье рассматриваются различные алгоритмы решения данной задачи, а также некоторые задачи, которые можно свести к данной задаче. Здесь мы рассмотрим эту методику применительно к нашей конкретной задаче. Научимся сначала искать длину наидлиннейшей возрастающей подпоследовательности, а восстановлением самой подпоследовательности займёмся чуть позже. Динамическое программирование для поиска длины ответа Для этого давайте научимся считать массив , где — это длина наидлиннейшей возрастающей подпоследовательности, оканчивающейся именно в элементе с индексом. Массив этот он и есть — сама динамика будем считать постепенно: В конце, когда этот массив будет подсчитан нами, ответ на задачу будет равен максимуму в массиве. Итак, пусть текущий индекс — , то есть мы хотим посчитать значение , а все предыдущие значения уже подсчитаны. Тогда заметим, что у нас есть два варианта: Тогда перед числом в искомой подпоследовательности стоит какое-то другое число. Давайте переберём это число: Пусть мы рассматриваем какой-то текущий индекс. Поскольку динамика для него уже подсчитана, получается, что это число вместе с числом даёт ответ. Таким образом, можно считать по такой формуле: Объединяя эти два варианта в один, получаем окончательный алгоритм для вычисления: Этот алгоритм — и есть сама динамика. Реализация Приведём реализацию описанного выше алгоритма, которая находит и выводит длину наидлиннейшей возрастающей подпоследовательности: Чтобы суметь восстановить ответ, помимо динамики надо также хранить вспомогательный массив — то, в каком месте достигся максимум для каждого значения. Иными словами, индекс будет обозначать тот самый индекс , при котором получилось наибольшее значение. Этот массив в динамическом программировании часто называют "массивом предков". Тогда, чтобы вывести ответ, надо просто идти от элемента с максимальным значением по его предкам до тех пор, пока мы не выведем всю подпоследовательность, то есть пока не дойдём до элемента со значением. Реализация восстановления ответа Итак, у нас изменится и код самой динамики, и добавится код, производящий вывод наидлиннейшей подпоследовательности выводятся индексы элементов подпоследовательности, в 0-индексации. Для удобства мы изначально положили индексы: Этот способ при реализации приводит к чуть более длинному коду, однако взамен получаем экономию памяти и абсолютное совпадение логики программы в процессе подсчёта динамики и в процессе восстановления. Динамика теперь будет такой: Изначально мы полагаем , а все остальные элементы. Считать эту динамику мы будем постепенно, обработав число , затем , и т. Приведём реализацию этой динамики за: Другое свойство — что каждый элемент обновляет максимум одну ячейку. Таким образом, это означает, что обрабатывать очередное мы можем за , сделав двоичный поиск по массиву. В самом деле, мы просто ищем в массиве первое число, которое строго больше , и пытаемся произвести обновление этого элемента аналогично приведённой выше реализации. Кроме того, для каждого элемента массива надо будет хранить его "предка" — то есть индекс того элемента, который должен стоять перед в оптимальной подпоследовательности. Поддерживая эти два массива по ходу вычисления динамики, в конце будет нетрудно восстановить искомую подпоследовательность. Интересно отметить, что применительно к данной динамике ответ можно восстанавливать только так, через массивы предков — а без них восстановить ответ после вычисления динамики будет невозможно. Это один из редких случаев, когда к динамике неприменим альтернативный способ восстановления — без массивов предков. В самом деле, давайте вернёмся к самой первой динамике, где состоянием являлась просто текущая позиция. Текущее значение динамики вычисляется как максимум значений среди всех таких элементов , что. Следовательно, если мы через обозначим такой массив , в который будем записывать значения динамики от чисел: Задача поиска максимума на префиксах массива с учётом того, что массив может меняться решается многими стандартными структурами данных, например, деревом отрезков или деревом Фенвика. Воспользовавшись любой такой структурой данных, мы получим решение за. У этого способа решения есть явные недостатки: Кроме того, если входные числа могут быть достаточно большими, то скорее всего их придётся сжимать то есть перенумеровывать от до — без этого многие стандартные структуры данных работать не смогут из-за высокого потребления памяти. С другой стороны, у данного пути есть и преимущества. Во-первых, при таком способе решения не придётся задумываться о хитрой динамике. Во-вторых, этот способ позволяет решать некоторые обобщения нашей задачи о них см. Смежные задачи Приведём здесь несколько задач, тесно связанных с задачей поиска наидлиннейшей возрастающей подпоследовательности. Наидлиннейшая неубывающая подпоследовательность Фактически, это та же самая задача, только теперь в искомой подпоследовательности допускаются одинаковые числа то есть мы должны найти нестрого возрастающую подпоследовательность. Решение этой задачи по сути ничем не отличается от нашей исходной задачи, просто при сравнениях изменятся знаки неравенств, а также надо будет немного изменить двоичный поиск. Количество наидлиннейших возрастающих подпоследовательностей Для решения этой задачи можно использовать самую первую динамику за либо подход с помощью структур данных для решения за. И в том, и в том случае все изменения заключаются только в том, что помимо значения динамики надо также хранить, сколькими способами это значение могло быть получено. По всей видимости, способ решения через динамику за к данной задаче применить невозможно. Наименьшее число невозрастающих подпоследовательностей, покрывающих данную Условие таково. Дан массив из чисел. Требуется раскрасить его числа в наименьшее число цветов так, чтобы по каждому цвету получалась бы невозрастающая подпоследовательность. Утверждается, что минимальное количество необходимых цветов равно длине наидлиннейшей возрастающей подпоследовательности. Фактически, нам надо доказать двойственность этой задачи и задачи поиска наидлиннейшей возрастающей подпоследовательности. Обозначим через длину наидлиннейшей возрастающей подпоследовательности, а через — искомое наименьшее число невозрастающих подпоследовательностей. Нам надо доказать, что. С одной стороны, понятно, почему не может быть: Докажем это от противного: Тогда рассмотрим любой оптимальный набор из невозрастающих подпоследовательностей. Преобразуем этот набор таким образом: Таким образом, через какое-то конечное число шагов у нас останется подпоследовательностей, причём их стартовые числа будут образовывать возрастающую подпоследовательность длины. Таким образом, в самом деле, , что и требовалось доказать. Утверждается, что само искомое разбиение на подпоследовательности можно искать жадно, то есть идя слева направо и относя текущее число в ту подпоследовательность, которая сейчас заканчивается на минимальное число, больше либо равное текущему.


1 7 промиллеэто сколько выпито
Журнал дежурства сторожей образец скачать
Номенклатурный номер материала где взять
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment