Учимося застосовувати цикли з лічильником до різних задач
Від програм з виведенням наперед заданих значень (зірочки, валентинки, задане слово...) перейдемо до створення програм, в яких виводжуваний результат буде формуватися в ході виконання самого циклу.
Користувач уводить з клавіатури натуральне число. Скласти програму, яка виведе перші 20 чисел натурального ряду, які поділяються на це число
Очевидно, що першим числом натурального ряду чисел, яке поділятиметься на дане число, буде саме це число. Якщо ввести, наприклад, число 11, то першим число, яке поділятиметься на 11 буде саме число 11 (11:11=1). Яке число наступне? А яке число треба розділити на 11, щоб отримати у відповіді 2? Зрозуміло, що це число 22 (22:11=2). Третім числом у цьому ряду буде 33 (33:11=3), четвертим - 44 (44:11=4) і т.д. Як бачимо, кожне наступне потрібне нам число можна отримати додаванням того числа, кратність якого нам потрібна:
Ось і відповідь на питання, що писати в тіло циклу: треба щоразу додавати те число, яке увів користувач, і виводити відповідь. І так 20 разів (кількість повторів циклу обумовлена умовою задачі).
Якщо позначимо число, яке ввів користувач як n1
, а число, яке буде виводити програма як n2
, то отримуємо такий алгоритм:
Розберемо роботу цього алгоритму на конкретних числах:
Ну й, нарешті, сама програма:
А можна щось у цій програмі вдосконалити?
Дана програма, дійсно, містить недолік. Наприклад, якщо уважно роздивитися надану вище таблицю, то можна помітити, що на останньому 20 кроці роботи циклу програма обчислює наступне, 21-ше число, яке нам не потрібне і не буде виводитися. Чи можна зробити так, щоб цього не робити?
Для цього треба розібратися, чому так виходить. Уся справа в тому, що в тілі циклу останньою є команда n2:=n2+n1
. От вона-то й "винна" у тому, що обчислюється зайве число. На останньому, 20-му кроці, останньою є команда, яка обчислює 21-ше число. Значить, треба просто зробити так, щоб останньою в тілі циклу була команда виведення результату. Просто поміняємо місцями команди в тілі циклу, перед "запуском" циклу додамо ще одну команду write(n2,' ');
і зменшимо кількість повторів тіла циклу (перше ж число нашого ряду вже виведене ще до старту циклічних обчислень):
program twenty_numbers_2;
var n1,n2,i:integer;
begin
writeln ('Введіть число: ');
read(n1);
n2 := n1;
writeln ('На ',n1,' поділяються числа: ');
write(n2,' ');
for i := 1 to 19 do
begin
n2 := n2+n1;
write(n2,' ');
end;
end.
Побачити цю програму "в дії" можна за цим посиланням. Щоправда, нічого нового ви не побачите. Виведення результату нічим не відрізнятиметься від попереднього, але тепер уже сама робота програми організована більш раціонально.
Звісно, що хороше - ворог кращого, але про те, як зробити свою роботу ще кращою, слід думати завжди. І не тільки в програмуванні 😉
Чи існує інший спосіб розв'язання цієї задачі?
Наявність двох і, навіть, більше варіантів - це досить звичне явище. От і в цьому випадку інший спосіб написати програму для цього випадку існує. Якщо ми ще раз повернемося до першого прикладу, розглянутого як ілюстрація до цієї задачі, то побачимо там такий ряд чисел, кратних числу 11:
11 22 33 44 55 66 77 88 99 ...
Що являють собою ці числа? На першому місці стоїть число 11, на другому - 22 (22=11*2
), на третьому - 33 (33=11*3
), на четвертому - 44 (44=11*4
) і т.д. Очевидно, що на двадцятому місці стоятиме число 11*20=220
. Таким чином, маємо, що кожне наступне число можна отримати множенням початкового числа на його порядковий номер:
Оскільки номером по порядку в нашому циклі виступає лічильник і
, значить. можемо його використати для обчислення наступного елемента нашого ряду чисел:
program twenty_numbers_3;
var n1,n2,i:integer;
begin
writeln ('Введіть число: ');
read(n1);
n2:=n1;
writeln ('На ',n1,' поділяються числа: ');
for i:=1 to 20 do
begin
n2:=n1*i;
write(n2,' ');
end;
end.
А шукати інший спосіб розв'язання задачі корисно завжди. І не тільки в програмуванні.
Користувач вводить з клавіатури перше число діапазону, кількість потрібних чисел та інтервал, через які потрібно виводити числа. Вивести увесь діапазон чисел.
Наприклад, користувач хоче вивести 8 чисел, перше з яких 3, а кожне наступне на 0,7 більше за попереднє. Що робить програма? Програма виводить ряд: 3 3,7 4,4 5,1 5,8 6,5 7,2 7,9
. Все.
Як бачимо, ця програма схожа на попередню: перше число не n1
, а якесь x
, кількість чисел не 20
, а n
, а кожне наступне число отримуємо додаванням до попереднього не того ж таки числа n1
, а деякого іншого (можливо й дробового!) числа h
.
Спробуйте написати цю програму самостійно, спираючись на код до Завдання 30
program diapazon;
var x,h:real; n,i:integer;
begin
write ('Введіть перше число: ');
readln(x);
write('Введіть кількість чисел: ');
readln(n);
write('Задайте інтервал: ');
readln(h);
for i:=1 to n do
begin
write(x,' ');
x:=x+h
end;
end.
От тепер, коли ми дізналися як знаходити усі числа, що утворюються за деяким правилом, можемо перейти до однієї з типових задач програмування, яка носить назву "цикл з накопиченням". Цикл з накопиченням характерний тим, що при черговому виконанні циклу нове значення змінної-результату буде залежати від значення цієї ж змінної, визначеної на попередній ітерації тіла циклу.
Розглянемо приклад:
Обчислити суму n чисел, починаючи з деякого числа x, якщо кожне наступне число більше за попереднє на y
Ця задача теж схожа на попередню. У ній так само потрібно за введеним з клавіатури першим числом, кількістю чисел в діапазоні й інтервалом обчислити усі числа діапазону. Тільки на цей раз їх потрібно не просто вивести на екран, а пододавати і вивести не самі ці числа, а їх суму. Так, з попереднім рядом, що був прикладом до Завдання 31, і який складається з 8-ми чисел, починається з числа 3 й має інтервал 0,7 потрібно виконати таке обчислення:
3 + 3,7 + 4,4 + 5,1 + 5,8 + 6,5 + 7,2 + 7,9 = 43,6
Відповідь 43,6 слід вивести на екран.
Зрозуміло, що ця задача має дві складові:
Як знайти числа ряду, ми уже знаємо. Дивимося в розв'язання Завдання 31 - там воно! От тільки незрозуміло, куди подіти уже знайдені числа нашого діапазону. Якщо вивести їх на екран, то як їх потім знову увести в програму? Команда read
"уміє" читати тільки введене з клавіатури. Ну не набирати ж їх користувачу вручну заново!
По секрету
Отут не зовсім вірно. Насправді, команда read
призначена не тільки для читання того, що введене з клавіатури. За допомогою команди read
можна також прочитати і вміст файлу. Якщо, наприклад, вивести числа нашого ряду у текстовий файл, то потім їх звідти ж можна ще раз прочитати. Але, по-перше, це не раціонально: з програми "вивантажувати" числа у файл, щоб потім з цього ж файлу "завантажувати" ці ж самі числа у цю ж саму програму! А по-друге, про роботу з файлами у нашому курсі не йдеться. Більше про запис даних у файл і читання з файлу можна прочитати ТУТ, ТУТ і ТУТ.
Ще одним варіантом є "завести" собі стільки змінних, скільки чисел у ряді і при отриманні кожного наступного числа присвоювати нове значення наступній змінній.
Усе це було б добре, якби усе не було так погано! Те, що цей спосіб провальний, видно неозброєним оком. Кількість-то чисел ряду задає користувач програми! Звідки ми знаємо, скільки чисел йому наступного разу заманеться обчислювати? Скільки змінних записати у розділі var
? Ну так, щоб на всі випадки вистачило! Сто? Тисячу? Мільйон? А не "задовбаємося" набирати мільйон змінних? До пенсії встигнемо?
Знову не той варіант! 😞
Для виходу з нашої безвиході є добра новина! Річ у тім, що УСІ комп'ютери й УСІ мови програмування придумали ЛЮДИ! Значить, у них - ЛЮДСЬКА ЛОГІКА! Тому, складаючи програму для комп'ютера, часто буває корисним задати собі питання: а як би я розв'язував/розв'язувала цю задачу, якби мені треба було виконати ці обчислення ВРУЧНУ?
А вручну ми б робили таке:
УРА! Ось воно рішення! Нам потрібна ще одна змінна, до якої ми будемо в циклі додавати кожне наступне знайдене число ряду. Після того як ми, як у коробку, "поскладаємо у цю змінну" усі наші числа, то в ній опиниться якраз те, що ми й шукали - сума усіх чисел ряду.
Позначимо нашу "коробочку", в якій будемо накопичувати суму, літерою s
(бо "сума") і запишемо код програми:
Зверніть увагу на команду s:=0;
в рядку 10. Це обнулення "коробочки" зроблене для того, щоб у разі повторного запуску цієї програми нові числа нового ряду не додавалися до результатів попереднього обчислення суми.
Ще раз уважно перечитайте код програми й переглядаючи демонстрацію, розберіться на конкретному прикладі з тим, як працює цей цикл:
Геометричною прогресією називається послідовність чисел, в якій кожне наступне число отримується шляхом множення попереднього числа на один і той самий множник (його називають знаменником геометричної прогресії). Обчислити суму чисел, що є членами такої послідовності, якщо відоме перше число, кількість чисел та знаменник геометричної прогресії.
Приклад: якщо перше число в геометричній прогресії дорівнює 2, знаменник 3, а всього таких чисел 8, тоді потрібно обчислити суму чисел 2 6 18 54 162 486 1458 4374
.
Ця програма повністю така ж, як і попередня і буде відрізнятися від неї лише ОДНИМ ОПЕРАТОРОМ! Здогадалися, яким?
program suma_prohresiji;
var x,y,s:real; n,i:integer;
begin
write('Задайте перше число діапазону: ');
readln(x);
write('Введіть кількість чисел діапазону: ');
readln(n);
write('Задайте множник: ');
readln(y);
s:=0; //Обнуляємо змінну, яка міститиме накопичувану суму
for i:=1 to n do //Задаємо цикл з n ітерацій
begin
s:=s+x; //Додаємо до суми поточне число
x:=x*y; //Обчислюємо наступне число МНОЖЕННЯМ - єдина відмінність!
end;
writeln(s:2:2) //Виводимо накопичену суму
end.
Згідно з однією давньою легендою, індійському цареві Шераму так сподобалася гра в шахи, що він вирішив щедро нагородити того, хто її придумав. Цар викликав до себе Сету (так за цією легендою звали винахідника гри в шахи) і запитав, яку ж винагороду той хотів би отримати. На це Сета відповів, що хотів би отримати винагороду пшеницею, причому пшеницю слід було порахувати таким чином: на першу клітинку шахової дошки покласти одну зернинку, на другу - дві, на третю - чотири і т.д. на кожну наступну клітинку класти удвічі більше, ніж на попередню і так до 64-ї.
До чого тут ця легенда? А до того, що увівши тепер умову цієї задачі (перше число - 1, кількість чисел - 64, множник - 2) в щойно створену програму до Завдання 33 ви зможете за долі секунди розв'язати проблему, над якою усі придворні математики царя Шерама працювали усю ніч і дізнатися, скільки ж зерняток пшениці мав отримати винахідник шахів. А якщо ще й обчислите масу цієї кількості пшениці (є така одиниця вимірювання маси - гран: маса зернятка; 1 гран - це приблизно 64,8 міліграма), тоді зрозумієте, чому ця винагорода ніколи не могла бути видана.
З Уроку 10 ви дізналися про те, що:
І рівень (на "6"):
Відомий тариф на перевезення одного пасажира в маршрутному таксі. Вивести у стовпчик вартість проїзду у маршрутному таксі для 1, 2, 3, ... , 10 пасажирів.
Підказка
Дивимося Завдання 30, враховуючи, що вартість проїзду двох пасажирів - це вартість проїзду одного, помножена на 2, вартість проїзду трьох - це вартість проїзду одного, помножена на 3 і т.д., а також те, що відповіді потрібно виводити в стовпчик (writeln
).
ІІ рівень (на "11"):
Факторіалом деякого числа n (позначається n!
) називають добуток усіх натуральних чисел від 1 до даного числа n, тобто, n!=1∙2∙3∙...∙n
. Наприклад, факторіалом числа 5 є добуток 5!=1∙2∙3∙4∙5=120
. Скласти програму для обчислення факторіала деякого, введеного користувачем, числа.
Підказка
Перше число в цьому ряду завжди одне й те саме - це число 1. Кількість чисел теж відома: для факторіала числа 5 таких чисел теж 5. Кожне наступне число ряду отримуємо додаванням одиниці до попереднього числа. На відміну від попередніх задач тут потрібно обчислювати не суму, а добуток. Словом, це Завдання 32 з дещо видозміненим тілом циклу і ще з одним уточненням, яке треба внести в рядок 10. Спробуйте самостійно здогадатися, яким, адже на це число потрібно буде множити, а тому подумайте, яким повинно бути значення цієї "коробочки" ДО ПОЧАТКУ роботи циклу.