Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика_всем

.pdf
Скачиваний:
75
Добавлен:
03.03.2016
Размер:
5.42 Mб
Скачать

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 Вывод чисел "пирамидой" – а) и анализ числа на встречаемость в его записи цифр – б)

4. Решение типовых задач на развилки и циклы

91

а во внутреннем – многократный вывод числа соответственно номеру строчки. Блок схема показана на Рисунок 4.15 а). Язык Pascal вот такой:

program BAC;

var i,j,N,k:integer; begin

writeLn('введите N'); readLn(N);

k:=1;

for i:=1 to N do begin

for j:=1 to i do write(k:5);

writeLn;

inc(k);

end;

end.

В результате мы увидим на консоли:

1

2

 

 

 

2

3

 

 

3

3

4

 

4

4

4

5

5

5

5

5

ПРИМЕР

Ввести число N, выяснить сколько раз цифра 3 входит в запись этого числа.

Алгоритм основан на последовательном рассмотрении остатка от деления на 10 младшего разряда рассматриваемого числа. Алгоритм представлен на (Рисунок 4.15 б)). Здесь переменная y хранит число равное целой части от деления текущего числа на 10. Переменная y1 – буферная переменная для хранения предыдущего (неделенного на 10) числа. Соответственно, остаток от деления проверяется для чисел y*10 и y1. Если остаток равен 3, то мы производим инкрементацию переменной k, в которой хранится количество встреченных троек.

program cifra3;

var x,y,y1,k,N:integer; begin

writeLn('введите N'); readLn(N);

y:=N;

while y>0 do begin

y1:=y;

y:=y1 div 10;

92

4.2 Задачи на использование циклов

x:= (y1-y*10) mod 10; if x=3 then

inc(k);

end;

writeLn('цифра3 вх. в число ',N,'всего ',k,' раз'); end.

Вот что будет на консоли в результате работы программы:

введите N 3331333

цифра 3 вх. в число 3331333 всего 5 раз

5.ОДНОМЕРНЫЕ МАССИВЫ

5.1Понятие и объявление массива

Винженерной деятельности приходится в основном работать с большими объемами информации. Для корректной обработки приходится использовать различные методики ее анализа и представления. Для представления больших объемов данных можно применить объединение их по некоторому признаку, в результате чего получится массив данных.

Впрограммировании массивами называют набор однотипных переменных объединенных общим названием. Элементы массива расположены в одном месте памяти и каждая переменная входящая в его состав имеет свой номер (индекс). Индекс в массиве может быть только целым числом.

Очень условно массив можно представить как состав поезда, в который включено некоторое количество вагонов. Как известно, каждый вагон имеет свой номер и этот номер представляет собой целое число. Т.е., например, не может быть вагона 2,5 или 5,78. В каждом вагоне содержится определенный груз и его можно переместить туда из другого места или наоборот извлечь.

Массив, у которого адрес (индекс) элемента представлен одним числом, называется одномерным. Если элементами одномерного массива являются простой числовой тип данных, то такие массивы называют векторами. Различные примеры одномерных массивов представлены на (Рисунок 5.1).

Для того чтобы в программе сделать объявление переменной типа одномерный массив, нужно в заголовке записать следующее:

Рисунок 5.1 Примеры одномерных массивов разных типов. В ячейках записаны элементы, под каждой ячейкой записан индекс элемента в массиве.

94

5.1 Понятие и объявление массива

ИмяПеременной: array [от..до] of ТипЭлементов;

Пример объявления массивов, изображенных на рисунке (Рисунок 5.1) запишем ниже

Var

A:array [1..8] of byte;

B:array [1..7] of real;

C:array [1..7] of boolean;

D:array [1..5] of string;

Здесь представлены переменные типа «массив», которые имеют в своем составе ровно столько элементов, сколько заявлено на рисунке (Рисунок 5.1). Однако, объявление переменной есть процесс выделения под нее памяти. Еще до начала работы программы мы должны знать, какого размера массив нам потребуется в процессе ее исполнения. К сожалению, не всегда заранее известно о точной его длине. Потому приходится использовать динамические массивы (которых мы пока касаться не будем), иные эвристические подходы или просто избыточное выделение памяти.

Избыточное выделение памяти есть действие, направленное на резервирование памяти достаточной для хранения наибольшего из предполагаемых массивов в процессе выполнения программы. Так, например, если нам нужно объявить переменную, в которой будут храниться средние рейтинговые оценки академической группы студентов в 100-бальной шкале, то логичным будет длину массива ограничить 40-ка элементами, поскольку, практически не встречается групп, состоящих более чем из 40-ка человек. Хотя реально может использоваться, скажем, 25 из 40 ячеек. Остальные ячейки просто будут занимать память и не использоваться. В итоге программа становится более массовой, т.е. менее чувствительной к качеству входных данных. К сожалению, в программировании, как и в других отраслях деятельности человека, часто приходится идти на компромиссы.

Кроме прямого объявления можно использовать объявление через вспомогательный раздел type. Приведем пример такого объявления для массивов изображенных на рисунке (Рисунок 5.1).

Const

LengthA = 40;

LengthB = 50;

LengthC = 120;

LengthD = 40;

Type

= array[1.. LengthA] of byte;

T1mByte

T1mRe

= array[1.. LengthB] of real;

T1mBool

= array[1.. LengthC] of boolean;

T1mStr

= array[1.. LengthD] of string;

Var

 

A:T1mByte;

B:T1mRe;

C:T1mBool;

D:T1mStr;