Прежде всего, поймите, какова основная идея рекурсии:
- Если мы можем решить проблему без рекурсии, решите ее и верните решение.
- Если мы не можем,затем сведите проблему к одной или нескольким более мелким задачам, рекурсивно решите каждую более мелкую проблему и объедините решения для решения более крупной проблемы.
Во-вторых, поймите, какова основная идея динамического программирования:
- Рекурсивные решения часто повторно вычисляют одну и ту же проблему много раз;иногда более эффективно хранить решение, а не пересчитывать его.
Хорошо, давайте приступим к вашей проблеме.
// Do not modify change
class Change
{
public long coin2 = 0;
public long bill5 = 0;
public long bill10 = 0;
}
Pish tosh.Этот класс ужасен .Исправьте это!
sealed class Change
{
public long Two { get; }
public long Five { get; }
public long Ten { get; }
public Change(long two, long five, long ten)
{
this.Two = two;
this.Five = five;
this.Ten = ten;
}
public Change AddTwo() => new Change(Two + 1, Five, Ten);
public Change AddFive() => new Change(Two, Five + 1, Ten);
public Change AddTen() => new Change(Two, Five, Ten + 1);
public long Count => Two + Five + Ten;
public long Total => Two * 2 + Five * 5 + Ten * 10;
}
Начните с структуры данных, которая вам помогает, а не с структуры, которая вас ранит .
Теперь давайте напишем рекурсивную функцию:
public static Change OptimalChange(long s)
{
// Are we in the base case? Solve the problem.
// If not, break it down into a smaller problem.
}
Какой базовый случай?На самом деле их два. Если сумма отрицательная, то решения не существует , а , если сумма равна нулю, то есть решение нуля .
public static Change OptimalChange(long s)
{
if (s < 0)
return null;
if (s == 0)
return new Change(0, 0, 0);
Хорошо, этолегкая часть.Что самое сложное?Ну, если есть решение, то или у него есть два, или у него есть пять, или у него есть десять, верно?Или, может быть, все три.Итак, давайте выясним.
public static Change OptimalChange(long s)
{
if (s < 0)
return null;
if (s == 0)
return new Change(0, 0, 0);
Change tryTen = OptimalChange(s - 10)?.AddTen();
...
Можете ли вы взять это отсюда?
Посмотрите, насколько легче становится проблема, когда у вас есть структура данных, которая реализует необходимые вам операции? Снова всегда создайте структуру данных, которая поможет вам .
Следующая проблема: Этот алгоритм очень неэффективен .Зачем?Потому что мы постоянно переделываем проблемы, которые мы уже сделали.Предположим, мы оцениваем OptimalChange (22).Это вызывает OptimalChange (12), который вызывает OptimalChange (7), который вызывает OptimalChange (5).Но OptionalChange (12) также вызывает OptimalChange (10), который снова вызывает OptimalChange (5).Ответ не изменился, но мы снова делаем вычисления.
Итак, что мы делаем? Мы используем метод динамического программирования .Есть два способа сделать это:
- Продолжать быть рекурсивным и запоминать рекурсивную функцию.
- Создать массив изменений и заполнять его по ходу работы.
Но подождите, проблем больше, чем проблем с производительностью.Мы делаем задачу меньше максимум на 10 и минимум на 2 каждый раз, но параметр длинный;это могут быть миллиарды или триллионы.Если у нас есть рекурсивное решение, мы взорвем стек, а если у нас будет решение на основе массива, оно будет слишком большим.
Нам нужно быть более умным, чтобы решить эту проблему в заданном диапазоневозможных входов .Подумай об этом тяжело; можем ли мы решить проблему аналитически, без рекурсии, массивов или длительных циклов ?Или, что то же самое, , есть ли способ быстро свести очень большие проблемы к мелким ?Небольшая проблема может быть решена с помощью динамического программирования.
Как и всегда с домашними заданиями , помните, что вы связаны правилами хорошей стипендии .Если вы используете идеи SO в своих решениях для домашних заданий, вы должны дать кредит .Невыполнение этого требования - плагиат, из-за которого вас исключат из приличной школы.