© К. Поляков, 2009-2013
B8 (повышенный уровень, время – 5 мин)
Тема: Анализ программы, содержащей подпрограммы,
циклы и ветвления.
Что нужно знать:
- операции целочисленного деления (div) и взятия остатка (mod)
- как работают операторы присваивания, циклы и условные операторы в языке программирования
Пример задания:
Ниже записан
алгоритм. После выполнения алгоритма
было напечатано 3 числа. Первые два
напечатанных числа – это числа
9 и 81. Какое наибольшее число может
быть напечатано третьим?
var x, y,
z: integer;
r, a, b: integer;
begin
readln(x,
у);
if
у > x then begin
z:= x; x:= у; у:= z;
end;
a:=
x; b:= y;
while
b > 0 do begin
r:= a mod b;
a:= b;
b:= r;
end;
writeln(a);
writeln(x);
write(у);
end.
Решение:
- сложность этой задачи состоит в том, чтобы разобраться в алгоритме
- сначала вводятся два числа и переставляются так, чтобы в переменной x было наибольшее число, а в переменной y – наименьшее из двух:
if
у > x then begin
z:= x; x:= у; у:= z;
end;
- затем исходные значения копируются в переменные a и b и с ними выполняется следующий алгоритм
while b > 0 do begin
r:= a mod b;
a:= b;
b:= r;
end;
его суть сводится к тому,
что меньшее из двух чисел, a и b, каждый раз заменяется на остаток от
деления большего на меньшее до тех пор,
пока этот остаток не станет равен нулю;
- делаем вывод, что это классический Алгоритм Евклида, который служит для вычисления наибольшего общего делителя (НОД) двух чисел; это делитель в результате оказывается в переменной a
- смотрим, что выводится на экран: сначала значение переменной a (наибольший общий делитель исходных чисел, НОД(x,y)), затем значение x (большее из исходных чисел) и значение y (меньшее из исходных чисел)
- по условию первое число – 9, второе – 81, поэтому третье число должно быть меньше, чем 81, и НОД(81,y) = 9
- наибольшее число, которое меньше 81 и делится на 9, равно 72 (обратите внимание, что исходные числа не могут быть равны, потому что в этом случае их НОД был бы равен 81)
- ответ: 72
Ещё пример задания:
Ниже записана
программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает
сначала 3, а потом 7.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=0;
while x > 0 do begin
L:=L+1;
if M < (x
mod 10) then begin
M:=x mod 10;
end;
x:= x div 10;
end;
writeln(L); write(M);
end.
Решение:
- для решения задачи необходимо понять, что делает эта программа
- если это не видно сразу, можно выполнить ручную прокрутку для какого-то простого числа, например, для числа 251:
оператор |
условие |
x |
L |
M |
readln(x); |
|
251 |
? |
? |
L:=0; M:=0; |
|
|
0 |
0 |
while x
> 0 do… |
251 > 0? да |
|
|
|
L:=L+1; |
|
|
1 |
|
if M<(x mod 10) then… |
M <(251 mod 10)? да |
|
|
|
M:=x mod
10; |
|
|
|
1 |
x:=x div
10; |
|
25 |
|
|
while x
> 0 do… |
25 > 0? да |
|
|
|
L:=L+1; |
|
|
2 |
|
if M<(x
mod 10) then… |
M <(25 mod 10)? да |
|
|
|
M:=x mod
10; |
|
|
|
5 |
x:=x div
10; |
|
2 |
|
|
while x
> 0 do… |
2 > 0? да |
|
|
|
L:=L+1; |
|
|
3 |
|
if M<(x
mod 10) then… |
M <(2 mod 10)? нет |
|
|
|
x:=x div 10; |
|
0 |
|
|
while x
> 0 do… |
0 > 0? нет |
|
|
|
writeln(L); write(M); |
|
|
3 |
5 |
- можно догадаться, что в результате работы программы в переменной L окажется число цифр числа, а в переменной M – наибольшая цифра, но это предположение нужно постараться доказать
- нужно вспомнить (и запомнить), что для целого числа
остаток от деления на 10 (x mod 10) – это последняя цифра в десятичной записи числа, а целочисленное деление (x div 10) отсекает последнюю цифру, то есть из 123 получается 12
- рассмотрим цикл, число шагов которого зависит от изменения переменной x:
while x > 0 do begin
...
x:= x div 10;
{ отсечение последней цифры }
end;
здесь оставлены только
те операторы, которые влияют на значение x
- из приведенного цикла видно, что на каждом шаге от десятичной записи x отсекается последняя цифра до тех пор, пока все цифры не будут отсечены, то есть x не станет равно 0; поэтому цикл выполняется столько раз, сколько цифр в десятичной записи введенного числа
- на каждом шаге цикла переменная L увеличивается на 1:
L:=L+1;
других операторов, меняющих
значение L, в программе нет; поэтому после завершения
цикла в переменной L действительно находится
количество цифр
- теперь разберемся с переменной M, которая сначала равна 0; оператор, в котором она меняется, выглядит так:
if
M < (x mod 10) then begin
M:=x mod 10;
end;
учитывая, что x mod 10 – это последняя цифра десятичной записи
числа, получается что если эта цифра больше,
чем значение M, она записывается в переменную
M;
- этот оператор выполняется в цикле, причем выражение x mod 10 по очереди принимает значения всех цифр исходного числа; поэтому после завершения циклам в переменной M окажется наибольшая из всех цифр, то есть наша догадка подтверждается
- итак, по условию задачи фактически требуется найти наибольшее трехзначное число, в котором наибольшая цифра – 7; очевидно, что это 777.
- ответ: 777.
Возможные
ловушки и проблемы:
- это очень неплохая задача на понимание, тут достаточно сложно «вызубрить» метод решения, можно только освоить последовательность (системность) анализа
- ручной прокрутки в такой задаче недостаточно, по её результатам можно угадать алгоритм, но можно и не угадать; в критическом случае можно сделать ручную прокрутку для нескольких чисел им попытаться понять закономерность
|
Ещё пример задания:
Ниже записана
программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает
сначала 3, а потом 120.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=1;
while
x > 0 do begin
L:=L+1;
M:= M*(x mod 8);
x:= x div 8;
end;
writeln(L);
write(M);
end.
Решение:
- для решения задачи необходимо понять, что делает эта программа; повторяя рассуждения из предыдущего примера, выясняем, что
- переменная L с каждым шагом цикла увеличивается на 1
- переменная x на каждом шаге цикла делится на 8 и остаток отбрасывается
поэтому можно сделать
вывод, что в конце цикла переменная L будет равна количеству цифр введенного
числа, записанного в восьмеричной системе
счисления; таким образом, восьмеричная
запись числа содержит ровно 3 цифры
- выражение x mod 8 – это последняя цифра восьмеричной записи числа; на каждом шаге цикла переменная M умножается на эту величину, поэтому в результате в M будет записано произведение всех цифр восьмеричной записи введенного числа
- по условию это произведение равно 120, то есть
, где a, b и с – числа от 0 до 7 (которые в восьмеричной системе счисления записываются одной цифрой)
- поскольку нам нужно наибольшее число, перебираем делители числа 120, начиная со старшей цифры – 7; видим, что 120 на 7 не делится, поэтому такой цифры в восьмеричной записи числа нет
- но 120 делится на 6, поэтому старшей цифрой может быть 6 – только в том случае, когда второй сомножитель можно представить в виде произведения двух чисел в интервале 1..6
- делим 120 на 6, получаем 20; это число представляется как произведение 5 и 4, каждое из этих чисел записывается в виде одной восьмеричной цифры, то есть, они нам подходят
- вспомним, что нас интересует максимальное число, поэтому цифры нужно выстроить в порядке убывания: 6548
- заметим, что мы получили число в восьмеричной системе, а ответ нужно дать в десятичной; переводим: 6548 = 6·82 + 5·81 + 4·80 = 428.
- ответ: 428.
Возможные
ловушки и проблемы:
- поскольку в цикле идет деление на 8, мы получаем цифры числа в восьмеричной системе; каждая из них должна быть в интервале 0..7 (не может быть 8 и 9)
- на последнем шаге нужно не забыть перевести число из восьмеричной системы в десятичную
|
Задачи для тренировки1:
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 7.
var x, L,
M: integer;
begin
readln(x);
L:=0;
M:=0;
while
x > 0 do begin
L:= L + 1;
M:= M + x mod 10;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 8.
var x, L,
M: integer;
begin
readln(x);
L:=0;
M:=0;
while
x > 0 do begin
L:= L + 1;
if x mod 2 = 0 then
M:= M + x mod 10;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 0.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=0;
while x > 0 do begin
L:= L + 1;
if x mod 2 =
0 then
M:= M + x mod 10;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 8.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=0;
while x > 0 do begin
L:= L + 1;
if x mod 2 =
1 then
M:= M + x mod 10;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 7.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=0;
while x > 0 do begin
L:= L + 1;
if x mod 2 =
0 then
M:= M + (x mod 10) div 2;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 7.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=0;
while x > 0 do begin
L:= L + 1;
if x mod 2 =
1 then
M:= M + (x mod 10) div 2;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 7.
var x, L,
M: integer;
begin
readln(x);
L:=0;
M:=0;
while
x > 0 do begin
L:=L+1;
if M < x then begin
M:=x mod 10;
end;
x:= x div 10;
end;
writeln(L); write(M);
end.
- Ниже записана программа. Получив на вход число
, эта программа печатает два числа,
и
. Укажите наибольшее из таких чисел
, при вводе которых алгоритм печатает сначала 3, а потом 8.
var x, L,
M: integer;
begin
readln(x);
L:=0; M:=0;
while x > 0 do begin
L:=L+1;
if (M < x)
and (x mod 2 = 0) then begin
M:=x mod 10;
end;