Мы с вами, уважаемые подписчики, рассмотрели уже немало алгоритмов и подпрограмм решения различных задач. Сегодня же мы должны убедиться в том, что они имеют не только самостоятельное значение, но и могут быть строительным материалом для других алгоритмов и подпрограмм, которые по этой причине мы будем называть комбинированными.
В соответствии с методом последовательного уточнения всегда целесообразно создавать такие алгоритмы, чтобы их можно было использовать при построении других более сложных алгоритмов.
КОМБИНИРОВАННЫЕ АЛГОРИТМЫ И ПОДПРОГРАММЫ
1. Решение задачи “Обмен трёх”.
Задача L.4.2. “Обмен трёх”. Построить алгоритм и подпрограмму обмена значений трёх переменных A, Bи Cтак, чтобы переменная Aприобретала значение переменной B, переменная Bприобретала значение переменной C, а переменная Cприобретала значение переменной A.
Предположим, что переменные задачи имеют такие значения: A = 5, B = 10, C = 15. В соответствии с условием задачи, в результате работы алгоритма, обменивающего значения этих трёх переменных, мы должны получить: A = 10, B = 15, C = 5.
Для решения задачи воспользуемся алгоритмом Обмен ( резA, B: <тип> ), который позволяет обменивать значениями две переменные (см. материалы занятия 13, алгоритм L.1.3).
Продолжим наш пример. Сначала используем алгоритм Обмен для обмена значений переменных A и B. При этом получим: A = 10, B = 5, C = 15. Сравнивая полученные значения с тем, что должно быть получено, приходим к выводу, что теперь следует обменять значения переменных B и C.
После этого задача оказывается решённой.
Алгоритм и его перевод на Паскаль выглядят следующим образом:
алг Обмен_3 ( рез A, B, C: <тип> ) нач Обмен ( A, B ); Обмен ( B, C ) кон
Procedure Exchange_3 ( Var A,B,C: T ); Begin Exchange ( A, B ); Exchange ( B, C ) End;
2. Решение задачи “Котангенс угла”.
Задача L.4.4. “Котангенс угла”. Заданы стороны треугольника a, b, c. Построить алгоритм и подпрограмму вычисления котангенса угла, лежащего против стороны a.
Котангенс угла можно вычислить, если известны значения косинуса и синуса этого угла, путём деления первого на второе.
Для вычисления косинуса угла A, лежащего против стороны a, воспользуемся алгоритмом CosineA ( a, b, c: вещ ): вещ (см. материалы занятия 14,
алгоритм L.1.6). Несложный анализ показывает, что при этом могут быть получены как положительные, так и отрицательные значения результата в пределах –1 < Cos(A) < 1. Это, в свою очередь, соответствует значениям угла A треугольника в пределах 0 < A < 180 (в градусах).
Известно, что значения синуса таких углов всегда положительны. Поэтому для вычисления синуса угла A может быть использовано известное соотношение Sin2a + Cos2a = 1. При этом, если |x|<1 – значение косинуса угла A, то Sqrt (1– x*x )>0 будет значением его синуса.
Если для заданных сторон треугольник существует, то указанные выше предельные значения величин и неравенства оказываются справедливыми, а значит деление на нуль или извлечение корня из отрицательного числа гарантированно отсутствуют.
Алгоритм и его перевод на Паскаль выглядят следующим образом:
алгCtgA ( a, b, c: вещ ): вещ начx: вещ x := CosineA (a, b, c); CtgA := x / Sqrt ( 1 – x*x ) кон
Function CtgA ( a, b, c: Real ): Real; Var x: Real; Begin x := CosineA (a, b, c); CtgA := x / Sqrt ( 1 – x*x ) End;
3. Решение задачи “Промежуток времени”.
Задача L.4.5. “Промежуток времени”. Известны два момента времени одних и тех же суток, выраженные в часах и минутах(Ч1, М1 и Ч2, М2 соответственно). Построить алгоритм и подпрограмму определения промежутка
времени между этими двумя моментами, выразив его также в часах и минутах.
Разберём для примера аналогичную задачу, используя денежные единицы. Как правило, материал такого содержания наиболее понятен всем.
Предположим, что из денежной суммы 8 долларов 17 центов нужно вычесть 4 доллара 82 цента. Для этого сначала нужно обе суммы представить в наиболее мелких денежных единицах, то есть в центах. Получим 817 и 482 цента соответственно. Выполнив вычитание, получим 335 центов. Для получения окончательного ответа выполним обратное преобразование к наиболее крупным денежным единицам, то есть
к долларам. В результате этого получим 3 доллара 35 центов.
Для представления заданных моментов времени в секундах, то есть в наиболее мелких единицах, воспользуемся алгоритмом Время_Сек( Ч, М, С: нат ): нат (см. материалы по ссылке http://a-morgun.narod.ru/a06-01/Glava_04.pdf
). Этот алгоритм выражает в полных секундах промежуток времени, выраженный в полных часах, минутах и секундах.
Указанный алгоритм и его перевод на Паскаль выглядят следующим образом:
алг Время_Сек ( Ч, М, С: нат ): нат нач Время_Сек := ( Ч * 60 + М ) * 60 + С кон
Function Time_Second ( H,M,S: LongInt ): LongInt; Begin Time_Second := ( H
* 60 + M ) * 60 + S End;
Для представления заданных моментов времени в секундах обращения к нему должны иметь вид Время_Сек ( Ч1, М1, 0) и Время_Сек ( Ч2, М2, 0). Нули на месте третьего параметра означают нулевые значения секунд, которые условием нашей задачи не заданы. Кроме того, поскольку условие задачи не указывает, какой из моментов времени является более ранним, то для
вычисления величины промежутка времени между ними в секундах должна использоваться разность этих моментов, взятая по абсолютной величине.
Для обратного перехода от секунд к более крупным единицам времени нужен уже алгоритм Сек_Время ( арг К: нат; рез Ч, М, С: нат ), который преобразует промежуток времени К из секунд в часы, минуты и секунды (см. материалы занятия 13, алгоритм L.3.1).
Для реализации обратного перехода следует использовать обращение к этому алгоритму в виде Сек_Время( К, Ч, М, С ). При этом на первом месте среди параметров обращения указан фактический параметр К, обозначающий модуль разности заданных моментов времени в секундах. Далее указываются параметры Ч и М
– нужные нам результаты. Так как результатами алгоритма получение значения секунд не предусмотрено, то на последнем месте для получения значения секунд используется промежуточная переменная С.
В окончательном виде алгоритм и его перевод на Паскаль выглядят следующим образом:
алг Промежуток ( арг Ч1, М1, Ч2, М2: нат ; рез Ч, М: нат) нач К, С: нат К := Abs ( Время_Сек ( Ч1, М1, 0 ) – Время_Сек ( Ч2, М2, 0 ) ); Сек_Время ( К, Ч, М, С ) кон
Procedure Interval ( H1, M1, H2, M2: LongInt; Var H: LongInt; Var M: Byte ); Var K: LongInt; C: Byte; Begin K := Abs ( Time_Second (H1, M1, 0) – Time_Second (H2, M2, 0) ); Second_Time
( K, H, M, C ) End;
Обратите внимание на правильный выбор типов параметров-результатов в обращениях к подпрограммам. В Паскале это имеет принципиальное значение (см. материалы занятия 8). При указании фактических параметров-результатов для них требуется точное совпадение типов с типами соответствующих формальных параметров-результатов. При обращении к процедуре Second_Time параметр-результат H
должен иметь тип LongInt, а параметры-результаты Mи C – тип Byte (см. материалы занятия 13, алгоритм L.3.1).
Решение данной задачи приведём также и в виде программы.
{$B+,D+,E+,I+,L+,N+,Q+,R+,X-} Program L_04_05; Function Time_Second ( H, M, S: LongInt ): LongInt; Begin Time_Second := ( H * 60 + M ) * 60 + S End; Procedure Second_Time(K:LongInt; Var Hour:LongInt; Var Minute,Second:Byte); Begin Second := K Mod 60; K := K Div 60; Minute := K Mod 60; Hour := K Div 60 End; Procedure Interval ( H1, M1, H2, M2: Byte; Var H: LongInt; Var M: Byte ); Var K: LongInt; C: Byte; Begin K := Abs ( Time_Second(H1,M1,0) - Time_Second(H2,M2,0) ); Second_Time (K, H, M, C); End; Var H1,M1,H2,M2: Byte; H: LongInt; M: Byte; Begin Write('Введите первый момент времени в часах и минутах: '); ReadLn(H1,M1); Write('Введите второй момент времени в часах и минутах: '); ReadLn(H2,M2); Interval ( H1, M1, H2, M2, H, M ); WriteLn('Промежуток времени = ',H,' час ',M,' мин'); End.
4. Решение задачи “Угловой интервал”.
Задача L.4.7. “Угловой интервал”. Часовая стрелка за некоторый интервал времени повернулась на угол Fрадиан. Построить алгоритм и подпрограмму для выражения этого интервала времени в полных сутках, часах и минутах.
Для преобразования угла поворота стрелки Fв соответствующий интервал времени К, выраженный
в секундах, можно использовать алгоритм Угол_Сек ( A: вещ, D: нат ): нат, параметрами которого являются значение угла A в радианах и количество секунд D, в течение которых данная стрелка совершает полный оборот (см. материалы занятия 14,
алгоритм L.3.4). Обращение к этой функции должно иметь вид К := Угол_Сек ( F, 12 * 60 * 60 ), где величина12 * 60 * 60 секунд соответствует часовой стрелке.
Чтобы выразить полученный интервал времени в полных часах, минутах и секундах, можно использовать алгоритм Сек_Время ( арг К: нат; рез Ч, М, С: нат ), который преобразует интервал времени К из секунд в полные часыЧ, минуты М и секунды С (см. материалы занятия 13, алгоритм L.3.1). Выделенные секунды С в качестве результата нам не нужны, поэтому для их обозначения
можно выбрать промежуточную переменную.
Теперь, чтобы представить этот же интервал в полных сутках, часах и минутах, нужно из выделенных полных часов Ч дополнительно выделить сутки Д, что осуществляется операцией Ч div 24. При этом в качестве нового значения Ч следует взять остаток Ч mod 24.
Указанный алгоритм и его перевод на Паскаль выглядят следующим образом:
алг Угловой_Интервал ( аргF: вещ ; рез Д, Ч, М: нат) нач К, С: нат К := Угол_Сек ( F, 12 * 60 * 60 ); Сек_Время ( К, Ч, М, С ); Д := Ч div 24; Ч := Ч mod 24 кон
Procedure Angle_Interval ( F: Real; Var Day,Hour: LongInt; Var Minute: Byte ); Var K: LongInt; C: Byte; Begin K := Angle_Second ( F, 12 * 60 * 60 ); Second_Time ( K, Hour, Minute,
C ); Day := Hour Div 24; Hour := Hour Mod 24 End;
Так же, как и в предыдущей задаче, обратите внимание на правильный выбор типов параметров-результатов в обращениях к подпрограммам.
5. Решение задачи “Смещённое кольцо”.
Задача L.4.9. “Смещённое кольцо”. Две концентрические окружности радиусами R1 и R2 с центрами в некоторой точке (a, b) образуют плоское кольцо. Построить алгоритм и подпрограмму для определения того,
принадлежит ли этому кольцу заданная точка с координатами (x, y). Считать, что точка, расстояние которой от центра окружностей совпадает с одним из радиусов, также принадлежит кольцу.
Решить эту задачу нам поможет алгоритм Кольцо ( x, y, R1, R2: вещ ): лог, параметрами которого являются координаты заданной точки и радиусы концентрических
окружностей с центрами в начале координат (см. материалы занятия 18, алгоритм L.2.5).
Для этого перейдём к новой системе координат с началом в точке (a, b), не меняя направления её осей относительно старой. В результате центры концентрических окружностей окажутся в начале новой системы координат, а координати заданной точки будут (x–a, y–b).
Таким образом, для решения нашей задачи достаточно правильно обратиться к уже имеющемуся алгоритму, а именно: Кольцо ( x–a, y–b, R1, R2).
6. Решение задачи “Вершины треугольника”.
Задача L.4.10. “Вершины треугольника”. На плоскости заданы три произвольные точки с координатами (xA, yA), (xB, yB) и (xC, yC).Построить алгоритм и подпрограмму для определения того, может ли существовать треугольник с вершинами в заданных точках.
На первый взгляд может показаться, что такой треугольник возможен всегда и поэтому вопрос задачи не имеет смысла. Однако, при более внимательном рассмотрении приходит в голову, что некоторые (или даже все) из заданных точек могут совпадать и тогда треугольник на них не построишь. А ещё один “несчастный” случай связан с тем, что все три точки могут просто укладываться на одну прямую.
Один из возможных универсальных способов решения данной задачи связан с предварительным определением расстояний между каждой парой из заданных точек. Рассматривая три полученных расстояния как длины сторон треугольника, можно поставить вопрос, может ли существовать треугольник с такими длинами сторон. А на такой вопрос мы уже умеем отвечать (см. материалы занятия 16, алгоритм L.2.1).
Для вычисления расстояния между двумя точками на плоскости можно воспользоваться алгоритмом Длина( xA, yA, xB, yB: вещ ): вещ (см. материалы по ссылке
http://a-morgun.narod.ru/a06-01/Glava_04.pdf ). Эта функция даёт длину отрезка между двумя точками A и B, координаты которых (xA, yA) и (xB, yB) соответственно.
Указанный алгоритм и его перевод на Паскаль выглядят следующим образом:
алг Длина ( xA, yA, xB, yB: вещ ): вещ нач Длина := Sqrt(Sqr(xB–xA)+Sqr(yB–yA)) кон
Function Length_Piese(xA,yA,xB,yB: Real): Real; Begin Length_Piese := Sqrt(Sqr(xB–xA)+Sqr(yB–yA)) End;
Таким образом, решая нашу задачу, нам следует трижды обратиться к алгоритму Длина для определения расстояний между каждой парой точек, а затем обратиться к алгоритму Стороны для ответа на основной вопрос.
Алгоритм и его перевод на Паскаль выглядят следующим образом:
алг Вершины ( xA, yA, xB, yB, xC, yC: вещ ): лог начa,b,c: вещ a := Длина ( xB, yB, xC, yC); b := Длина ( xA, yA, xC, yC); c := Длина ( xA, yA, xB, yB); Вершины := Стороны ( a, b, c) кон
Function Apex(xA,yA,xB,yB,xC,yC: Real): Boolean; Var a,b,c: Real; Begin a := Length_Piese( xB, yB, xC, yC ); b := Length_Piese( xA, yA, xC, yC ); c := Length_Piese( xA, yA, xB, yB ); Apex := Side ( a, b, c ) End;
Построить программы решения всех рассмотренных задач рекомендуется выполнить самостоятельно.
Уважаемые подписчики! Не кажется ли вам, что столь большое число разработанных нами подпрограмм требует их хранения в составе некоторых библиотек? Ответ на этот важный вопрос мы рассмотрим на одном из ближайших занятий.
Уважаемые подписчики!При необходимости задать вопрос, проконсультироваться, уточнить или обсудить что-либо обращайтесь через Гостевую книгу моего персонального сайта http://a-morgun.narod.ru