Разбор задачи D. Пизанская башня
Тема: динамическое программирование
Сложность: ниже среднего
1 способ: вывод рекуррентной формулы
Вручную для n от 1 до 5 находим минимальное количество перекладываний.
n | 1 | 2 | 3 | 4 | 5 |
кол-во ходов m | 1 | 3 | 5 | 9 | 15 |
Далее, видим, что зависимость можно описать формулой mi .
var n,i:integer;
m:array[1..40]of int64;
begin
read(n);
m[1]:=1;
m[2]:=3;
for i:=1 to n do
m[i]:=m[i-2]+m[i-1]+1;
writeln(m[n]);
end.
2 способ: запоминающая функция
Чтобы переложить n дисков со столбика a на столбик b, нужно сначала переложить n-1 диск на столбик 6-a-b, затем переложить n-й диск на столбик b, затем все диски со столбика 6-a-b на столбик b. Чтобы повторно не вычислять результат функции количества перекладываний для некоторого набора аргументов (n, a, b), функция должна запоминать в массиве результаты предыдущих вычислений. Размерность массива для запоминания должна совпадать с количеством аргументов функции и областью определения аргументов.
var n:integer;
_nmoves:array[1..40,1..3,1..3] of int64; { для запоминания результата }
function nmoves(n,a,b:integer):int64;
begin
if _nmoves[n,a,b]=0 then
if (n=1) or (a=2) then
_nmoves[n,a,b]:=1
else
_nmoves[n,a,b]:=nmoves(n-1,a,6-a-b)+1+nmoves(n-1,6-a-b,b);
nmoves:=_nmoves[n,a,b]
end;
begin
read(n);
writeln(nmoves(n,1,3));
end.