Рекурсия: различия между версиями
Содержимое удалено Содержимое добавлено
Karagota (обсуждение | вклад) |
Karagota (обсуждение | вклад) |
||
Строка 97:
Эту задачу можно встретить и под названием «Золотая гора» — нужно спуститься с горы и собрать как можно больше золота.
Можно заметить, что в любом месте горы начинается гора меньшего размера, будем называть такие горы ''горками''. Пусть число a(i,j) есть число в треугольнике, находящееся в i-й строчке на j-м месте, а число (i,j) есть максимальное значение суммы, которое можно получить спускаясь с горки, начиная с этого элемента. Понятно, что (i,j) есть число a(i,j) плюс максимум из двух вариантов: (i+1,j) и (i+1,j+1). Эти два варианта соответствуют тому, что мы можем спуститься вниз-вправо или вниз-влево. Получилось рекурсивное определение: <math>S(i,j)=a(i,j)+\max(S(i+1,j),\;S(i+1, j+1)).</math> На основе этой рекуррентной формулы можно написать рекурсивный алгоритм. Но нужно быть осторожным. Попробуем вычислить время работы нашего алгоритма при входных данных максимального размера — 100 строк. Рекурсивный алгоритм вычисления функции <math>(.,.)</math> перебирает все возможные пути. Сколько их? На каждом шаге есть возможность выбрать один вариант из двух (направо или налево). Количество шагов равно количеству строк треугольника. Значит, количество всех путей равно <math>2^{
Строка 104:
На рисунке обозначены две горки (треугольники): одна с вершиной в числе 3, другая с вершиной в числе 8. Эти горки пересекаются, и их пересечение тоже горка с вершиной в числе 1. Можно заметить, что при вычислении самого лучшего пути по рекурсивному алгоритму горка с вершиной в числе 1 будет использоваться дважды. Для горок с вершинами в нижних строчках повторных вызовов будет ещё больше. Это и есть причина медленности работы алгоритма.
Решить эту задачу за разумное время помогает '''динамическое программирование'''. Суть динамического программирования хорошо описана в книге Р. Беллмана {{Ref|Bell}}. Есть и более современные учебники {{Ref|2}},{{Ref|3}}, в них можно найти много интересных алгоритмов, основанных на динамическом программировании.
Общая идея динамического программирования заключается в том, что мы рассматриваем вместо одной задачи целое семейство задач. Это семейство задач у нас будет таким: найти наилучший путь из вершины (i,j). Для каждой пары i,j получим одну задачу. При i=1 и j=1 получается исходная задача, которую нам нужно решить. '''Начнём решать эти задачи с простых: сначала для нижней строчки, затем второй снизу и так далее, пока не дойдём до самой верхней строчки треугольника'''.
|