Информатика / лекции
.pdf4. Решение типовых задач на развилки и циклы |
81 |
program ddd; var x,y,z:real; begin
writeLn('табуляция функции cos(y*sin(x*x*x)):'); y:=-2;
while y<=1 do begin
x:=13;
while x<=15 do begin
z:=cos(y*sin(x*x*x)); if z<0.6 then
writeLn('z(',x:6:3,', ',y:6:3,') =',z:6:2); x:=x+0.8;
end;
y:=y+1;
end;
end.
В результате на консоли появится сообщение:
табуляция функции cos(y*sin(x*x*x)): z(13.000, -2.000) = -0.14
z(13.800, -2.000) = -0.40 z(14.600, -2.000) = -0.28 z(13.800, -1.000) = 0.55 z(13.800, 1.000) = 0.55
Рассмотрим еще одну интересную задачу.
ПРИМЕР
Для функции y =ex / x2 где x изменяется от точки x =1 с шагом x = 0,5 в положительном направлении, определить на каком шаге будет выполнено условие y >104 .
Решение задачи достаточно простое и представлено на блок-схеме
(Рисунок 4.10).
Программная реализация: program ddd;
var x,y:real; k:integer;
begin
x:=1; k:=0; repeat
y:=exp(x)/sqr(x);
inc(k);
x:=x+0.5; until y>1e4;
writeLn('условие достигается в точке ', x:8:1); writeLn('на ',k,'-м шаге' );
end.
82 4.2 Задачи на использование циклов
|
Начало |
|
В результате получим такой ответ: |
|||||||||
|
|
|
|
|||||||||
|
|
|
|
условие |
достигается |
в |
точке |
|||||
|
|
|
|
|||||||||
|
|
|
|
|||||||||
|
x := 1 |
|
15.5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
на 29-м шаге |
|
|
|
|
||||
|
|
|
|
Как |
уже |
отмечалось |
ранее, |
при |
||||
|
k := 0 |
|
||||||||||
|
|
программировании |
циклов |
важную |
роль |
|||||||
|
|
|
|
|||||||||
|
|
|
|
играют рекуррентные формулы, которые |
||||||||
|
|
|
|
достаточно |
просто |
|
позволяют получить |
|||||
|
|
|
|
|
||||||||
|
|
|
|
|
||||||||
|
y := ex/x2 |
|
значение |
|
элемента |
|
некоторой |
|||||
|
|
|
|
последовательности |
методом |
вычисления |
||||||
|
|
|
|
всех ее членов начиная с первого и |
||||||||
|
|
|
|
|||||||||
|
k := k + 1 |
|
заканчивая тем, который нам необходим в |
|||||||||
|
|
|
|
конкретной |
|
задаче. |
Эти |
формулы |
||||
|
|
|
|
использовались абсолютно во всех задачах на |
||||||||
|
|
|
|
|||||||||
|
x := x + 0.5 |
|
циклы, которые здесь были рассмотрены. |
|||||||||
|
|
|
|
Напомним, что рекуррентной называется |
||||||||
|
|
|
|
|||||||||
|
|
|
|
такая последовательность, у которой каждый |
||||||||
|
y > 104 |
|
последующий ее член основан на значении |
|||||||||
|
|
|
|
предыдущего. |
Это |
означает, |
что |
|||||
|
|
|
|
рекуррентными будут, в частности, все те |
||||||||
|
|
|
|
|||||||||
|
Вывод x, k |
|
операции присваивания, у которых слева от |
|||||||||
|
|
операции стоит |
переменная |
встречающаяся |
||||||||
|
|
|
|
справа. Наиболее часто используемая форма |
||||||||
|
|
|
|
|||||||||
|
|
|
|
|||||||||
|
Конец |
|
рекуррентной записи – это форма |
|||||||||
|
|
|
|
рекуррентного подсчета суммы. В задачах на |
||||||||
|
Рисунок 4.10 Поиск шага на |
табуляцию |
таковой |
формой |
обладают |
|||||||
котором монотонная функция |
действия |
по |
изменению |
аргумента ( |
||||||||
|
превысит некоторый порог |
x := x + |
x ). Изменение значения переменной |
|||||||||
инкрементацией. Если |
|
по |
такой |
|
формуле |
называют |
||||||
переменная |
не |
увеличивается, |
а уменьшается |
|||||||||
(используется формула |
x := x − |
x ), то действие зазывается декрементацией. |
Стоит отметить, что даже поиск максимума, по своей сути рекуррентен, поскольку каждое последующее его значение основано на предыдущем (хотя и не так явно, как в операциях присваивания).
Практически всегда, когда производят расчет суммы, за начальное значение принимают ноль. Рассмотрим, например, такую задачу:
ПРИМЕР
6
Найти значение суммы S = ∑k 2 . Расписывается эта сумма достаточно
k =1
просто S =12 + 22 +32 + 42 +52 +62 . В результате будем иметь 91. Блок схема изображена на (Рисунок 4.11 а)).
|
|
4. Решение типовых задач на развилки и циклы |
83 |
|||||||||
|
|
Начало |
|
|
Начало |
|
|
|||||
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
ввод N |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
||
|
|
S := 1 |
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
P := 1 |
|
|
|
|
|
k := 1 , 6 |
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
k := 1 , N |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
||
|
|
S := S+k2 |
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
P := P*2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
вывод S |
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
вывод P |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
Конец |
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a) |
|
|
Конец |
б) |
Рисунок 4.11 Задачи на поиск суммы (а)) и произведения (б))
program SumS; var s:real;
k,N:integer; begin
s:=0;
for k:=1 to 6 do s:=s+sqr(k);
writeLn('сумма равна ', s:8:2); end.
При решении задач на произведения в качестве начального значения принимают 1.
ПРИМЕР
Найти значение выражения P = 2N не используя операцию возведения в
N
степень. Эта задача эквивалентна расчету такой формулы: ∏2 = 2 2 2 ... 2
k =1
(всего N двоек). Решение показано на (Рисунок 4.11 б)). program PrP;
var k,N:integer; P:longInt;
begin
writeLn('введите N'); readLn(N);
p:=1;
84 4.2 Задачи на использование циклов
for k:=1 to N do p:=p*2;
writeLn('2 в степени ',N,' равно ', p); end.
Более интересной представляется задача на вложенные циклы, где прежде чем рассчитать значение по внешней рекуррентной формуле, приходится использовать внутреннюю.
ПРИМЕР
N |
2k |
|
|
|
|
Найти значение суммы S = ∑ k |
∑cos( j ) . |
|
|
|
|
k =1 |
j=k |
|
|
|
|
Здесь для подсчета внешней суммы каждый раз придется пересчитывать |
|||||
внутреннюю. При решении внешнюю |
обозначим |
переменной |
S _ ext , |
а |
|
внутреннюю, соответственно, S _ int . |
Структурно |
получается |
«сумма |
в |
сумме», что отражено на блок-схеме (Рисунок 4.12). Программа выглядит так:
program ddd;
var S_ext,S_int:real; k,N,j:integer;
begin
writeLn('введите N');
Начало
Ввод N
S_ext := 0
k := 1 , N
1
расчет S_int
2
S_ext := S_ext + k*S_int
Вывод S_ext
Конец
Шаг 1-2 расчет S_int
S_int := 0
j := k ,2k
S_int := S_int + cos(j)
Рисунок 4.12 Задача на вложенные суммы
4. Решение типовых задач на развилки и циклы |
85 |
readLn(N); S_ext:=0;
for k:=1 to N do begin
S_int:=0;
for j:=k to 2*k do S_int:=S_int+cos(j);
S_ext:=S_ext+k*S_int; end;
writeLn('сумма равна ', S_ext:8:2); end.
Иногда, несмотря на кажущуюся сложность, задача решается несколько проще, чем полагалось изначально.
ПРИМЕР
Найти значение суммы S = ∑N k 2 .
k =1 k!
Здесь для подсчета внешней суммы потребуется на каждой новой итерации вычислять факториал для текущего значения k . На первый взгляд, без вложенного цикла на произведение не обойтись. Однако, если посмотреть внимательно на формулу и вспомнить замечательное свойство факториала заключающееся в том, что для вычисления последующего значения достаточно знать предыдущее, то алгоритм запишется намного короче (Рисунок 4.13 а)). И, что самое главное, без вложенных циклов.
На комбинацию program ddd; var s:real;
f,k,N:integer; begin
cls; writeLn('введите N'); readLn(N);
s:=0;
f:=1;
for k:=1 to N do begin
f:=f*k;
s:=s+sqr(k)/f;
end;
writeLn('сумма равна ', s:8:2); end.
ПРИМЕР
Найти значение выражения x + x + x +... (всего 20 корней).
Для вычисления этого выражения необходимо самостоятельно придумать рекуррентную формулу. Это уже будет и не сумма и не произведение, а нечто более сложное. Чтобы понять, какая формула здесь
86 |
|
|
4.2 Задачи на использование циклов |
|||||||
|
|
|
Начало |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ввод N |
|
|
|
|
Начало |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S := 0 |
|
|
|
|
Ввод X |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
f := 1 |
|
|
|
|
S := 0 |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
k := 1 , N |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
k := 1 , 100 |
|||
|
|
|
|
|||||||
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
f := f*k |
|
|
|
|
S := S + X |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S := S + k2/f
Вывод S
Вывод S
|
Конец |
а) |
б) |
Конец
Рисунок 4.13 Сложная сумма - а) и нестандартная рекуррентная формула - б)
применяется, можно последовательно начать расписывать вычисляемое значение на каждом шаге. Итак,
|
i=1, S1 = |
x ; |
|
|
|
|
|
|
|
i=2, S2 = |
x + |
x = |
x + S1 ; |
|
|
|
|
|
i=3, S3 = |
x + |
x + |
x = x + S2 ; |
|
|
|
|
|
… |
|
|
|
|
|
|
|
|
i=k, S1 = x + Sk −1 ; |
|
|
|
|
|
||
|
… |
|
|
|
|
|
|
|
|
i=20, S20 = x + S19 ; |
|
|
|
|
|
||
|
Видна рекуррентная зависимость S := |
x + S . |
Осталось определить |
|||||
точку |
входа. |
Этой |
точкой, |
очевидно, |
будет |
S0 = 0 , |
поскольку |
|
S1 = |
x + S0 = |
x . |
Теперь, зная |
вид рекуррентной |
зависимости |
и точку |
начальное значение, достаточно просто составить алгоритм для вычисления
S (Рисунок 4.13 б)).
4. Решение типовых задач на развилки и циклы |
87 |
Программа представлена ниже: program sqrtS;
var k:integer; x,s:real;
begin cls;
writeLn('введите x'); readLn(x);
s:=0;
for k:=1 to 20 do s:=sqrt(x+s);
writeLn('s равно ', s); end.
При x=30 сумма получается равной 6, а, например, при x=7, она становится такой: 3.19258240356725.
Весьма интересными являются задачи на перекрестные рекуррентные зависимости. Перекрестными рекуррентными зависимостями называют такие, у которых каждое последующее значение вычисляется на основе нескольких предыдущих значений. Самый простой пример – это авторегрессионные последовательности. Наиболее известная последовательность задаваемая рекуррентно на основе двух предыдущих значений является последовательность Фибоначчи. Последовательность задается таким образом: a1 =1 , a2 =1, a3 = a1 + a2 , a4 = a3 + a2 , ak = ak −2 + ak −1 .
ПРИМЕР
Вывести 10 первых членов последовательности Фибоначчи.
Решается задача в один цикл. Решение представлено на (Рисунок 4.14
а)).
Ниже идет программа: program ddd;
var ak_3,ak_2,ak_1,ak:real; k:integer;
begin ak_2:=1; ak_1:=1; k:=2;
writeln(1:5,' z=',ak_1); writeln(2:5,' z=',ak_2); repeat
ak:=ak_1+ak_2; ak_2:=ak_1; ak_1:=ak; inc(k);
writeln(k:5,' z=',ak); until k=10;
end.
88 |
4.2 Задачи на использование циклов |
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рисунок 4.14 Последовательность Фибоначчи - а) и последовательность основанная на трех предыдущих членах
Результат таков:
1z=1
2z=1
3z=2
4z=3
5z=5
6z=8
7z=13
4. Решение типовых задач на развилки и циклы |
89 |
8z=21
9z=34
10z=55
Можно несколько модифицировать предыдущую последовательность и сделать так, чтобы в авторегрессионной формуле участвовало три предыдущих члена.
ПРИМЕР
Вывести N ( N ≤3 ) первых членов последовательности заданной рекуррентно ak = ak −1 + ak −2 + ak −3 , a1 =1 , a2 = 2 , a3 =3.
При решении этой задачи важно понять суть перехода от пары переменных к трем. В алгоритме на каждой итерации применяется так называемый циклический сдвиг переменных. Т.е. переменные принимают значения тех, которые им предшествуют. Ну а самая последняя, т.е. текущая переменная принимает свое значение согласно заданной рекуррентной формуле (Рисунок 4.14 б)). Имена переменным даны согласно порядку их расположения в последовательности, т.е. ak = ak , ak −1 = ak _1, ak −2 = ak _ 2 ,
ak −3 = ak _ 3 . Программа такова:
program ddd;
var ak_3,ak_2,ak_1,ak:real; k,N:integer;
begin
writeLn('введите N'); readLn(N);
while N<=3 do begin
writeLn('введите N'); readLn(N);
end; ak_3:=1; ak_2:=2; ak_1:=3; k:=3;
writeln(1:5,' z=',ak_3); writeln(2:5,' z=',ak_2); writeln(3:5,' z=',ak_1); repeat
ak:=ak_1+ak_3+ak_2; ak_3:=ak_2; ak_2:=ak_1; ak_1:=ak;
inc(k);
writeln(k:5,' z=',ak); until k=N;
end.
90 |
4.2 Задачи на использование циклов |
ПРИМЕР
Вывести числа от 1 до N построчно, причем в первой строке число выводится 1 раз, во второй выводится двойка 2 раза, в третьей тройка 3 раза и т.д. В строке N число N выводится N раз.
Для решения этой задачи потребуется использование вложенного цикла. Во внешнем цикле будет происходить изменение значения выводимого числа,
|
Начало |
|
Ввод N |
Начало |
|
|
y := N; k:=0 |
Ввод N |
|
k := 1 |
|
|
y > 0 |
i := 1 , N |
|
j := 1 , i |
y1 := y |
|
|
Вывод k |
y := y1 div 10 |
|
|
|
x := (y1-y*10) mod 10 |
Перевод |
|
строки |
|
|
x = 3 |
k := k+1 |
|
|
k := k + 1 |
Конец |
|
|
Вывод N, k |
а) |
б) |
|
Конец |
Рисунок 4.15 Вывод чисел "пирамидой" – а) и анализ числа на встречаемость в его записи цифр – б)