Задачи без массивов

В данной теме предлагаются решения простых задач с наименьшим числом действий (выполяемых операторов присваивания).

Задача 1. Дано число а и натуральное число n. Вычислить аn (a в степени n).

Решение:
k:=0; b:=1;
while k<>n do
begin
k:=k+1;
b:=b*a;
end;

Другое решение этой задачи:
k:=n;b:=1;
while k<>0 do
begin
k:=k-1;
b:=b*a;
end;

Число выполняемых операторов присваивания равно n.

Задача 2. Решить предыдущую задачу, если требуется, чтобы число действий (выполняемых операторов присваивания) было порядка log2n (то есть не превосходило бы C·log2n, где С -константа, log2n - это степень, в которую нужно возвести 2, чтобы получить n).

Решение:
k:=n; b:=1; c:=a;
while k<>0 do
begin
if k mod 2=0 then
begin
k:=k div 2;
c:=c*c;
end
else
begin
k:=k-1;
b:=b*c;
end;
end;

За каждые два вхождения в цикл значение переменной k уменьшается по крайней мере вдвое. В цикле выполняется 2 операции присваивания. Поэтому общее число действий не превосходит 4·log2n.

Задача 3. Дано натуральное число n, вычислить n! (1!=1, n!=n·(n-1)!).

Решение:
k:=n; b:=1;
while k<>0 do


begin
b:=b*k;
k:=k-1;
end;

Задача 4. Дано натуральное n, вычислить 1/1!+...+1/n! так, чтобы число операций (выполняемых команд присваивания) было бы порядка n (не более C·n для некоторой константы С).

Решение: Важно не вычислять заново каждый раз n!.

n!=1·2·3· ... ·(n-1)·n=(n-1)!·n. В нашем примере 1/n!=1/((n-1)!·n), т.е. каждый j элемент получается делением (j-1)-го элемента на j.

k:=1; sum:=0; last:=1; {1/1!}
while k<=n do
begin
sum:=sum+last;
k:=k+1;
last:=last/k;
end;

Число выполняемых операций присваивания равно 3·n.

Задача 5. Даны два натуральных числа а и b, не равные нулю одновременно. Вычислить d=НОД(а,b) - наибольший общий делитель а и b.

Решение: Алгоритм Евклида. Будем считать, что

для всех а,b>=0.
(см. Основы информатики и вычислительной техники, часть 1, под ред. А.П. Ершова и В.М. Монахова или А.Г. Кушниренко и др. Основы информатики и вычислительной техники)
m:=a; n:=b;
while not ((m=0) or (n=0)) do
if m>=n then m:=m-n else n:=n-m;
if m=0 then d:=n else d:=m;

Задача 6. Даны два натуральных числа а и b, не равные нулю одновременно. Найти d=НОД(а,b) и такие x и y, что d=a·x+b·y.

Решение: Добавим переменные p, q, r, s такие, что m=p·a+q·b, n=r·a+s·b.
m:=a; n:=b; p:=1; q:=0; r:=0; s:=1;
while not ((m=0) or (n=0)) do
if m>=n then
begin
m:=m-n; p:=p-r; q:=q-s;
end
else
begin
n:=n-m; r:=r-p; s:=s-q;
end;
if m=0 then
begin
k:=n; x:=r; y:=s;
end
else
begin
k:=m; x:=p; y:=q;
end;

Задача 7. Даны натуральные числа n и k, n>1. Напечатать k десятичных знаков числа 1/n. Программа должна использовать только целые переменные.

Решение: Сдвинув в десятичной записи числа 1/n запятую на k мест вправо, получим число (10k)/n. Нам надо напечатать его целую часть, то есть разделить 10k на n нацело. Стандартный способ требует использования больших по величине чисел, которые могут выйти за границы диапазона представимых чисел.

Воспользуемся методом "деления уголком" и будем хранить "остаток" r.

t:=0; r:=1;
while t<>k do
begin
write((10·r) div n);
r:=(10·r) mod n;
t:=t+1;
end;

Задача 8. Функция f с натуральными аргументами и значениями определена так: f(0)=0, f(1)=1, f(2n)=f(n), f(2n+1)=f(n)+f(n+1). Составить программу вычисления f(n) по заданному n, требующую порядка log2n операций (не более C·log2n).

Решение: Функцию f можно записать в общем виде: f(n)=a·f(k)+b·f(k+1).
Если n - четное, то а=1, b=0 иначе а=1, b=1.
Для k=2m: f(k)=f(m), f(k+1)=f(2m+1)=f(m)+f(m+1).
Тогда f(n)=a·f(k)+b·f(k+1)=a·f(m)+b·(f(m)+f(m+1))=(a+b)·f(m)+b·f(m+1).
Для k=2m+1: f(k)=f(m)+f(m+1), f(k+1)=f(2m+2)=f(2(m+1))=f(m+1).
Тогда f(n)=a·f(k)+b·f(k+1)=a·f(m)+(a+b)·f(m+1).
k:=n; a:=1; b:=0;
while k<>0 do
if k mod 2=0
then begin
m:=k div 2;
a:=a+b;
k:=m;
end
else begin
m:=k div 2;
b:=a+b;
k:=m;
end;

{k=0: f(n)=af(0)+bf(1)=b, что и требовалось}

При каждом вхождении в цикл значение переменной k уменьшается вдвое. Поэтому число операций не более 3·log2n.

Упражнения:

1. Последовательность Фибоначчи определяется так: a0=0, a1=1, ak=ak-1+ak-2 при k>=2.
Дано n. Вычислить a
n. Число операций должно быть порядка log2 n.
2. Написать вариант алгоритма Евклида, использующий соотношения НОД(2a,2b)=2НОД(a,b),
НОД(2a,b)=НОД(a,b) при нечетном b, использующий лишь деление на 2 и проверку четности. Число действий должно быть порядка log
2n для исходных данных, не превосходящих n.

Другие записи

10.06.2016. Cписок литературы
  1. Александров В.В. Рисунок, чертеж, картина на ЭВМ. - Л., Машиностроение, 1987г. 2. Аммерал Л. Принципы программирования в машинной графике. -М., Сол Систем, 1992г. 3. Арсак Ж. Программирование игр…