Как в информатике найти простое число

Алгоритмы поиска простых чисел

Время на прочтение
6 мин

Количество просмотров 134K

«Самое большое простое число 232582657-1. И я с гордостью утверждаю, что запомнил все его цифры… в двоичной форме».
Карл Померанс

Натуральное число называется простым, если оно имеет только два различных делителя: единицу и само себя. Задача поиска простых чисел не дает покоя математикам уже очень давно. Долгое время прямого практического применения эта проблема не имела, но все изменилось с появлением криптографии с открытым ключом. В этой заметке рассматривается несколько способов поиска простых чисел, как представляющих исключительно академический интерес, так и применяемых сегодня в криптографии.

Решето Эратосфена

Решето Эратосфена — алгоритм, предложенный древнегреческим математиком Эратосфеном. Этот метод позволяет найти все простые числа меньше заданного числа n. Суть метода заключается в следующем. Возьмем набор чисел от 2 до n. Вычеркнем из набора (отсеим) все числа делящиеся на 2, кроме 2. Перейдем к следующему «не отсеянному» числу — 3, снова вычеркиваем все что делится на 3. Переходим к следующему оставшемуся числу — 5 и так далее до тех пор пока мы не дойдем до n. После выполнения вышеописанных действий, в изначальном списке останутся только простые числа.

Алгоритм можно несколько оптимизировать. Так как один из делителей составного числа n обязательно

$leqslant sqrt{n}$, алгоритм можно останавливать, после вычеркивания чисел делящихся на

$sqrt{n}$.

Иллюстрация работы алгоритма из Википедии:

image

Сложность алгоритма составляет

$O(n loglog n)$, при этом, для хранения информации о том, какие числа были вычеркнуты требуется

$O(n)$ памяти.

Существует ряд оптимизаций, позволяющих снизить эти показатели. Прием под названием wheel factorization состоит в том, чтобы включать в изначальный список только числа взаимно простые с несколькими первыми простыми числами (например меньше 30). В теории предлагается брать первые простые примерно до

$sqrt{log n}$. Это позволяет снизить сложность алгоритма в

$loglog n$ раз. Помимо этого для уменьшения потребляемой памяти используется так называемое сегментирование. Изначальный набор чисел делится на сегменты размером

$leqslant sqrt{n}$ и для каждого сегмента решето Эратосфена применяется по отдельности. Потребление памяти снижается до

$O(sqrt{n})$.

Решето Аткина

Более совершенный алгоритм отсеивания составных чисел был предложен Аткином и Берштайном и получил название Решето Аткина. Этот способ основан на следующих трех свойствах простых чисел.

Свойство 1

Если n — положительное число, не кратное квадрату простого числа и такое, что

$n equiv 1(mod 4)$. То n — простое, тогда и только тогда, когда число корней уравнения

$4x^2+y^2=n$ нечетно.

Свойство 2

Если n — положительное число, не кратное квадрату простого числа и такое, что

$n equiv 1(mod 6)$. То n — простое, тогда и только тогда, когда число корней уравнения

$3x^2+y^2=n$ нечетно.

Свойство 3

Если n — положительное число, не кратное квадрату простого числа и такое, что

$n equiv 11(mod 12)$. То n — простое, тогда и только тогда, когда число корней уравнения

$3x^2-y^2=n$ нечетно.

Доказательства этих свойств приводятся в этой статье.

На начальном этапе алгоритма решето Аткина представляет собой массив A размером n, заполненный нулями. Для определения простых чисел перебираются все

$x, y < sqrt n$. Для каждой такой пары вычисляется

$4x^2+y^2$,

$3x^2+y^2$,

$3x^2-y^2$ и значение элементов массива

$A[4x^2+y^2]$,

$A[3x^2+y^2]$,

$A[3x^2-y^2]$ увеличивается на единицу. В конце работы алгоритма индексы всех элементов массива, которые имеют нечетные значения либо простые числа, либо квадраты простого числа. На последнем шаге алгоритма производится вычеркивание квадратов оставшихся в наборе чисел.

Из описания алгоритма следует, что вычислительная сложность решета Аткина и потребление памяти составляют

$O(n)$. При использовании wheel factorization и сегментирования оценка сложности алгоритма снижается до

$O(n / loglog n)$, а потребление памяти до

$O(sqrt{n})$.

Числа Мерсенна и тест Люка-Лемера

Конечно при таких показателях сложности, даже оптимизированное решето Аткина невозможно использовать для поиска по-настоящему больших простых чисел. К счастью, существуют быстрые тесты, позволяющие проверить является ли заданное число простым. В отличие от алгоритмов решета, такие тесты не предназначены для поиска всех простых чисел, они лишь способны сказать с некоторой вероятностью, является ли определенное число простым.

Один из таких методов проверки — тест Люка-Лемера. Это детерминированный и безусловный тест простоты. Это означает, что прохождение теста гарантирует простоту числа. К сожалению, тест предназначен только для чисел особого вида

$2^p-1$, где p — натуральное число. Такие числа называются числами Мерсенна.

Тест Люка-Лемера утверждает, что число Мерсенна

$M_p=2^p-1$ простое тогда и только тогда, когда p — простое и

$M_p$ делит нацело

$(p-1)$-й член последовательности

$S_k$ задаваемой рекуррентно:

$S_1=4, S_k=S_{k-1}^2-2$ для

$k > 1$.

Для числа

$M_p$ длиной p бит вычислительная сложность алгоритма составляет

${displaystyle O(p^{3})}$.

Благодаря простоте и детерминированности теста, самые большие известные простые числа — числа Мерсенна. Самое большое известное простое число на сегодня —

$2^{82,589,933}-1$, его десятичная запись состоит из 24,862,048 цифр. Полюбоваться на эту красоту можно здесь.

Теорема Ферма и тест Миллера-Рабина

Простых чисел Мерсенна известно не очень много, поэтому для криптографии с открытым ключом необходим другой способ поиска простых чисел. Одним из таким способов является тест простоты Ферма. Он основан на малой теореме Ферма, которая гласит, что если n — простое число, то для любого a, которое не делится на n, выполняется равенство

$a^{n-1}equiv 1{pmod {n}}$. Доказательство теоремы можно найти на Википедии.

Тест простоты Ферма — вероятностный тест, который заключается в переборе нескольких значений a, если хотя бы для одного из них выполняется неравенство

$a^{n-1} notequiv 1 pmod n$, то число n — составное. В противном случае, n — вероятно простое. Чем больше значений a использовано в тесте, тем выше вероятность того, что n — простое.

К сожалению, существуют такие составные числа n, для которых сравнение

$a^{n-1}equiv 1{pmod {n}}$ выполняется для всех a взаимно простых с n. Такие числа называются числам Кармайкла. Составные числа, которые успешно проходят тест Ферма, называются псевдопростыми Ферма. Количество псевдопростых Ферма бесконечно, поэтому тест Ферма — не самый надежный способ определения простых чисел.

Тест Миллера-Рабина

Более надежных результатов можно добиться комбинируя малую теорему Ферма и тот факт, что для простого числа p не существует других корней уравнения

$x^2 equiv 1 pmod p$, кроме 1 и -1. Тест Миллера-Рабина перебирает несколько значений a и проверяет выполнение следующих условий.

Пусть p — простое число и

$p-1=2^sd$, тогда для любого a справедливо хотя бы одно из условий:

  1. $a^{d}equiv pm1{pmod {p}}$
  2. Существует целое число r < s такое, что $a^{2^{r}d}equiv -1{pmod {p}}$

По теореме Ферма

$a^{p-1}equiv1pmod p$, а так как

$p-1=2^sd$ из свойства о корнях уравнения

$x^2 equiv 1 pmod p$ следует что если мы найдем такое a, для которого одно из условий не выполняется, значит p — составное число. Если одно из условий выполняется, число a называют свидетелем простоты числа n по Миллеру, а само число n — вероятно простым.

Чем больше свидетелей простоты найдено, тем выше вероятность того, что n — простое. Согласно теореме Рабина вероятность того, что случайно выбранное число a окажется свидетелем простоты составного числа составляет приблизительно

$1/4$.

Следовательно, если проверить k случайных чисел a, то вероятность принять составное число за простое

$approx(1/4)^k$.

Сложность работы алгоритма

$O(klog^3p)$, где k — количество проверок.

Благодаря быстроте и высокой точности тест Миллера-Рабина широко используется при поиске простых чисел. Многие современные криптографические библиотеки при проверке больших чисел на простоту используют только этот тест и, как показал Мартин Альбрехт в своей работе , этого не всегда оказывается достаточно.

Он смог сгенерировать такие составные числа, которые успершно прошли тест на простоту в библиотеках OpenSSL, CryptLib, JavaScript Big Number и многих других.

Тест Люка и Тест Baillie–PSW

Чтобы избежать уязвимости, связанные с ситуациями, когда сгенерированное злоумышленником составное число, выдается за простое, Мартин Альбрехт предлагает использовать тест Baillie–PSW. Несмотря на то, что тест Baillie–PSW является вероятностным, на сегодняшний день не найдено ни одно составное число, которое успешно проходит этот тест. За нахождение подобного числа в 1980 году авторы алгоритма пообещали вознаграждение в размере $30. Приз пока так и не был востребован.

Ряд исследователей проверили все числа до

$2^{64}$ и не обнаружили ни одного составного числа, прошедшего тест Baillie–PSW. Поэтому, для чисел меньше

$2^{64}$ тест считается детерминированным.

Суть теста сводится к последовательной проверке числа на простоу двумя различными методами. Один из этих методов уже описанный выше тест Миллера-Рабина. Второй — тест Люка на сильную псевдопростоту.

Тест Люка на сильную псевдопростоту

Последовательности Люка — пары рекуррентных последовательностей

${U_{n}(P,Q)}, {V_{n}(P,Q)}$, описываемые выражениями:

${displaystyle U_{0}(P,Q)=0,quad U_{1}(P,Q)=1,quad U_{n+2}(P,Q)=Pcdot U_{n+1}(P,Q)-Qcdot U_{n}(P,Q),,ngeq 0}$

${displaystyle V_{0}(P,Q)=2,quad V_{1}(P,Q)=P,quad V_{n+2}(P,Q)=Pcdot V_{n+1}(P,Q)-Qcdot V_{n}(P,Q),,ngeq 0}$

Пусть

$U_n(P,Q)$ и

$V_n(P,Q)$ — последовательности Люка, где целые числа P и Q удовлетворяют условию

${displaystyle D=P^{2}-4Qneq 0}$

Вычислим символ Якоби:

$left({frac {D}{p}}right)=varepsilon$.

Найдем такие r, s для которых выполняется равенство

$n-ε=2^rs$

Для простого числа n выполняется одно из следующих условий:

  1. n делит $U_s$
  2. n делит $V_{2^js}$ для некоторого j < r

В противном случае n — составное.

Вероятность того, что составное число n успешно пройдет тест Люка для заданной пары параметров P, Q не превышает 4/15. Следовательно, после применения теста k раз, эта вероятность составляет

$(4/15)^k$.

Тесты Миллера-Рабина и Люка производят не пересекающиеся множества псевдопростых чисел, соответственно если число p прошло оба теста, оно простое. Именно на этом свойстве основывается тест Baillie–PSW.

Заключение

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

$10^8$. Затем для каждого числа p из списка, с помощью теста Люка-Лемера, на простоту проверяется

$M_p=2^p-1$.

Чтобы сгенерировать большое простое число в криптографических целях, выбирается случайное число a и проверяется тестом Миллера-Рабина или более надежным Baillie–PSW. Согласно теореме о распределении простых чисел, у случайно выбранного числа от 1 до n шанс оказаться простым примерно равен

${frac {1}{ln n}}$. Следовательно, чтобы найти простое число размером 1024 бита, достаточно перебрать около тысячи вариантов.

P.S. Исходники

Реализацию всех описанных алгоритмов на Go можно посмотреть на GitHub.

Описание задачи

Программа принимает на вход число и проверяет, простое оно или нет.

Решение задачи

  1. Принимаем на вход число и записываем его в отдельную переменную.
  2. Инициализируем переменную, которая будет выполнять роль счетчика, значением 0.
  3. Организуем цикл for в диапазоне от 2 до значения проверяемого числа, деленного на 2 (речь идет, конечно, о целочисленном делении).
  4. Затем находим количество делителей нашего числа. При помощи условного оператора if мы проверяем, делится ли число без остатка, и затем, если делится, увеличиваем наш счетчик на единицу.
  5. Если число делителей равно 0, то проверяемое число является простым.
  6. Выводим результат на экран.
  7. Конец.

Исходный код

Ниже дан исходный код, который осуществляет проверку числа на простоту. Результаты работы программы также даны ниже.

a = int(input("Введите число: "))
k = 0
for i in range(2, a // 2+1):
    if (a % i == 0):
        k = k+1
if (k <= 0):
    print("Число простое")
else:
    print("Число не является простым")

Объяснение работы программы

  1. Пользователь вводит число, и оно сохраняется в переменную a.
  2. Инициализируем переменную k значением 0. Эта переменная будет выполнять роль счетчика.
  3. Запускаем цикл for в диапазоне от 2 до значения проверяемого числа, деленного на 2 (речь идет, конечно, о целочисленном делении). Напоминаем, что само число и 1 делителями мы считать не будем.
  4. Затем, при помощи инструкции if, на каждой итерации цикла мы проверяем, делится ли наше число без остатка на числа из выбранного диапазона цикла. Если делится, то переменная k, выполняющая роль счетчика, увеличивается на единицу.
  5. Если число делителей равно 0, то проверяемое число является простым.
  6. Выводим полученный результат на экран.

Результаты работы программы

Пример 1:
Введите число: 7
Число простое
 
Пример 2:
Введите число: 35
Число не является простым

Еще более 50 задач на числа в нашем телеграм канале Python Turbo. Уютное сообщество Python разработчиков.

Простые числа – это натуральные числа, большие единицы, которые имеют только два делителя: единицу и само это число.

Примеры простых чисел: 2 , 3, 5, 7, 11, 13…

(Единица не является простым числом!)

Существует множество задач, связанных с простыми числами, и хотя формулируются они достаточно просто, решить их бывает очень трудно. Некоторые свойства простых чисел еще не открыты. Это побудило немецкого математика Германа Вейля (Wayl, 1885-1955) так охарактеризовать простые числа: «Простые числа – это такие существа, которые всегда склонны прятаться от исследователя».

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

Не будем гнаться за рекордами, а рассмотрим несколько алгоритмов нахождения простых чисел.

Задача 1. Определение простого числа.

Составить программу, которая будет проверять, является ли введенное число простым.

Самый простой путь решения этой задачи – проверить, имеет ли данное число n (n >= 2) делители в интервале [2; n-1]. Если делители есть, число n – составное, если – нет, то – простое. При реализации алгоритма разумно делать проверку на четность введенного числа, поскольку все четные числа делятся на 2 и являются составными числами, то, очевидно, что нет необходимости искать делители для этих чисел. Логическая переменная flag в программе выступает в роли “флаговой” переменной и повышает наглядность программы, так, если flag = true, то n –простое число; если у числа n есть делители, то “флаг выключаем” с помощью оператора присваивания flag:= false, таким образом, если flag = false, то n – составное число.

  var  
  n,i: longint;
  flag: boolean;
  begin  writeln('vvod n');
  read(n);  
  if n = 2 then flag := true
         else if not odd (n) then flag :=  false           
         else  begin                 
              flag := true;                 
              for i := 2 to n-1 do                 
              if n mod i = 0 then flag  := false                 
              end;
  if flag then writeln('Yes') else writeln('No'); 
  readln;
  end.

Задача 2. Нахождение простых чисел в заданном интервале.

Составить программу, которая напечатает все простые числа в заданном интервале [2, m], для m>3 и подсчитает их количество.

Для реализации данного алгоритма необходимо проверить каждое число, находящееся в данном интервале, — простое оно или нет. Однако для этого машине пришлось бы потратить много времени. Поэтому подумаем, каким образом можно оптимизировать алгоритм, описанный в задаче 1, применительно к задаче 2?

Будем использовать следующие приемы оптимизации алгоритма:

  1. рассматривать только нечетные числа;
  2. использовать свойство: наименьшее число, на которое делится натуральное число n, не превышает целой части квадратного корня из числа n;
  3. прерывать работу цикла, реализующего поиск делителей числа, при нахождении первого же делителя с помощью процедуры Break, которая реализует немедленный выход из цикла и передает управление оператору, стоящему сразу за оператором цикла.

Как правило, учащиеся сами догадываются о приемах №1 и №3, но не всегда знают, как реализовать в программе досрочное завершение цикла, прием же №2 для них не очевиден, поэтому, возможно, учителю следует остановиться на нем более подробно или же привести полное доказательство этого утверждения.

Счетчик чисел будет находиться в переменной k. Когда очередное простое число найдено, он увеличивается на 1. Простые числа выводятся по 10 в строке, как только значение счетчика становится кратным 10, курсор переводится на новую строку.

 var
 m,n,i,k: longint;
 flag: boolean;
 begin
 writeln('vvod m>3');
 readln(m);
 write('      2      3');
 n:=3; k := 2;  n := n+2;
 while n <= m do begin
 flag := true;
 for i := 2 to round(sqrt(n)) do
   if n mod i = 0 then begin flag :=  false;
                    break
                end;
   if flag then begin
                write(n:7);
                k := k+1;
                if k mod 10 = 0 then writeln
                end;
 n := n+2
 end;
 writeln;
 writeln('kol-vo = ',k);
 readln
 end.

Близнецы

Два нечетных простых числа, разнящихся на два, называются близнецами. Близнецами являются, например, числа 5 и 7, 11 и 13, 17 и 19 и т.д. В начале натурального ряда такие пары чисел встречаются достаточно часто, но, по мере того как мы продвигаемся в область больших чисел, их становится все меньше и меньше. Известно, что в первой сотне имеется целых 8 близнецов, дальше они расположены очень неравномерно, их можно обнаружить все реже и реже, гораздо реже, нежели сами простые числа. До сих пор неясно, конечно ли число близнецов. Более того, еще не найден способ, посредством которого можно было бы разрешить эту проблему.

Задача 3. Поиск пар чисел близнецов.

Написать программу, которая будет находить все числа близнецы в интервале [2; 1000] и подсчитывать количество пар чисел близнецов.

Фактически будем использовать алгоритм и программу Задачи 2. В этом алгоритме нужно использовать дополнительные переменные для хранения двух “последних” простых чисел и проверять условие наличия близнецов – их разность должна быть равна двум.

 var
 m,n,n1,n2,i,k: longint;
 flag: boolean;
 begin
 m :=1000;
 n1 := 2; n2 := 3; n := n2+2; k:=0;
 while n <= m do begin
 flag := true;
 for i := 2 to round(sqrt(n)) do
   if n mod i = 0 then begin flag := false;
                    break
                end;
   if flag then begin  n1 := n2; n2 := n;
                 if (n2 -n1) = 2 then  begin
                               k := k+1;
                               write(n1:4,n2:4,' ');
                               if k mod 5 = 0 then writeln
                               end
             end;
 n := n+2
 end;
 writeln;
 writeln('kol -vo par =',k);
 readln
 end.

Задача 4. Нахождение простых чисел в заданном интервале с выводом в выходной файл.

Реализовать алгоритм задачи 2 с выводом простых чисел в выходной файл по 10 в строке. Последняя строка файла должна содержать информацию о количестве простых чисел в заданном интервале.

 var
 m,n,i,k: longint;
 flag: boolean;
 f:text;
 begin
 assign(f,'output.txt'); rewrite(f);
 writeln('vvod m > 3');
 readln(m);
 write(f,'  2  3');
 n:=3; k := 2;  n := n+2;
 while n <= m do begin
 flag := true;
 for i := 2 to round(sqrt(n)) do
   if n mod i = 0 then begin flag := false;
                    break
                end;
   if flag then begin
            write(f,n:7);
            k := k+1;
            if k mod 10 = 0 then  writeln(f)
            end;
 n := n+2
 end;
 writeln(f);
 writeln(f,'kol-vo = ',k);
 close(f)
 end.

Задача 5. Приемы оптимизации алгоритма задачи 4.

Оптимизировать алгоритм задачи 4 следующим образом: найденные простые числа записывать в файл, делимость очередного кандидата проверять только на числа из этого файла.

Словесное описание алгоритма:

  1. Вводим правую границу диапазона – m;
  2. Записываем двойку и тройку в файл;
  3. Пока очередное нечетное число i <= m :
    1. проверять очередное нечетное число на наличие делителей из данного файла;
    2. если есть делители, рассматривать очередное нечетное число, если нет — производить дозапись в “хвост” файла.
  4. По окончании просмотра диапазона ( i > m ), вывести в файл количество простых чисел.
{Простые  до m}
   label n1;
   var 
   m,i,j,k,q : longint;
   f : text;
   begin
      assign(f,'output.txt');
      rewrite(f);
      Writeln('vvod  m');  {m – правая граница диапазона чисел}
      readln(m);
      k := 0;             {k – счетчик количества  простых чисел}
      if  m >= 2 then begin
                   write(f,'  ':6,'2',' ':6);
                   k:=k+1
                 end;
      if m >= 3 then begin
                  write(f,'3');
                  k:=k+1
                end;
      close(f);
      i:=5;                {В i находится текущее  нечетное число}
      while  i <= m do
       begin  
        reset(f);
         {проверка делимости i на простые числа  q из файла}
         for j:=1  to k do
           begin
            read(f,q);
            if (q*q>i) then break;
            if (i mod q=0) then goto n1
           end;
        close(f); 
             {дозапись в ‘хвост’ файла простых  чисел}
        append(f);
            k:=k+1;
            Write (f,i:7);
            if k mod 10 = 0 then  writeln(f);
            close(f);
        {следующее нечетное число I  <= m}
        n1: i:=i+2
        end;
       {дозапись в конец файла количества простых  чисел} 
        append(f);
   writeln(f);
   writeln(f,'     kol -vo = ',k);
   close(f)
   end.

Эратосфеново решето 

Греческий математик Эратосфен (275-194 гг. до н.э.) предложил интересный метод нахождения простых чисел в интервале [2; n]. Он написал на папирусе, натянутом на рамку, все числа от 2 до 10000 и прокалывал составные числа. Папирус стал, как решето, которое “просеивает” составные числа, а простые оставляет. Поэтому такой метод называется Эратосфеновым решетом. Рассмотрим подробнее этот метод. 

Пусть написаны числа от 2 до n:

2 3 4 5 6 7 8 9 10 11 12 . . .

Первое неперечеркнутое число в строке является простым. Таким образом, 2 – простое число. Начинаем “просеивание” с него, перечеркивая все числа, которые делятся на 2:

2 3 4 5 6 7 8 9 10 11 12 . . .

Далее берем следующее по порядку неперечеркнутое число и перечеркиваем все числа, кратные ему и т. д. Таким образом, мы перечеркнем все составные числа, а простые останутся неперечеркнутыми:

2 3 4 5 6 7 8 9 10 11 12 . . .

Все числа указанного интервала можно рассматривать как множество и в дальнейшем из этого множества будем исключать (отсеивать) все составные числа.

Задача 6. Нахождение простых чисел с помощью решета Эратосфена.

Реализовать алгоритм решета Эратосфена с помощью организации работы с множествами.

Словесное описание алгоритма:

  1. Выделим из первых n натуральных чисел все простые числа (решето Эратосфена).
  2. Вначале формируем множество BeginSet, состоящее из всех целых чисел в диапазоне от 2 до n. Множество PrimerSet будет содержать искомые простые числа.
  3. Затем циклически повторим действия:
    1. взять из BeginSet первое входящее в него число next и поместить его в PrimerSet;
    2. удалить из BeginSet число next и все другие числа, кратные ему, т. е. 2* next, 3* next и т. д.

Цикл повторяется до тех пор, пока множество BeginSet не станет пустым. Программу нельзя использовать для произвольного n, т. к. в любом множестве не может быть больше 256 элементов. (Для расширения интервала простых чисел можно разбить одно большое множество на несколько маленьких, т. е. представить большое множество в виде массива малых множеств. Этот случай рассматривать не будем. Можно предложить наиболее заинтересованным учащимся самостоятельно рассмотреть этот вариант.)

{Выделение всех простых чисел из первых n целых}
 const
 n = 255; {Количество элементов исходного множества}
 type
 SetOfNumber = set of 1..n;
 var
 n1, next, i: word;                    {Вспомогательные  переменные}
 BeginSet,                             {Исходное  множество}
 PrimerSet: SetOfNumber;               {Множество простых чисел}
 begin
   BeginSet := [2..n];                 {Создаем исходное множество}
   PrimerSet  :=[2];                 {Поместить в PrimerSet  первое число из BeginSet}
   next := 2;                          {Первое простое  число}
    while BeginSet  <> [] do            {Начало  основного цикла}
          begin
           n1 := next;   {n1 –число, кратное  очередному простому (next)}
            {Цикл удаления из исходного  множества непростых чисел:} 
           while n1  <= n do
  begin
  Exclude(BeginSet,n1);
  n1 := n1+next         {Следующее кратное}
  end;        {Конец цикла  удаления}
  Include(PrimerSet,next);
  {Получение следующего простого, которое  есть первое невычеркнутое
  из исходного множества}

  repeat
  Inc(next);
  until  (next in BeginSet) or (next > n)
  end;  {Конец основного цикла}
  {Вывод результатов:}

  for  i := 1 to n do
  if i in PrimerSet then write(i:5);
  readln
  end.

Литература:

  1. Е.В. Андреева Методика обучения основам программирования на уроках информатики. Лекции 1-8. – М.: Педагогический университет «Первое сентября», 2006.
  2. В.А. Дагене, Г.К. Григас, А.Ф. Аугутис 100 задач по программированию. – М.: Просвещение, 1993. — 255 с.
  3. В.В. Фаронов Турбо Паскаль 7.0. Начальный курс. Учебное пособие. – М.: «Нолидж», 1999. — 616 с.

Содержание

  • Задача №1
  • Алгоритм определения простого числа
  • Реализация алгоритма определения простого числа в C#
  • Пример определения простых чисел из диапазона от 1 до N
  • Пример определения заданного количества простых чисел
  • Итого

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Простое число — это целое положительное число, имеющее ровно два различных натуральных делителя — единицу и самого себя. Определение того является ли число простым или нет — это одна из самых распространенных задач, решаемых в рамках курса лабораторных работ по информатике. Ниже будет представлена реализация алгоритма поиска простых чисел в C#, а также использование различных циклов для вывода простых чисел.

Задача №1

Проверить является ли число простым и вывести результат вычисления в консоль.

Алгоритм определения простого числа

Для того, чтобы проверить является ли число N простым необходимо:

  1. Задаем значение N
  2. Задаем цикл for от 2 до N-1 (счётчик цикла обозначим, например, как i)
    1. Если остаток от деление N на i равен нулю, то число не является простым — выходим из цикла
    2. Если остаток от деления N на i не равен нулю, то переходим к следующей итерации цикла
  3. Если цикл полностью пройден, то число является простым.

Метод определения простого числа в C#, реализующий представленный выше алгоритм может быть представлен следующим образом:

public bool IsPrime(int number)
{
    for (int i = 2; i < number; i++)
    {
        if (number % i == 0)
            return false;
    }
    return true;
}

Пример определения простых чисел из диапазона от 1 до N

Если по условиям задачи конечное значение диапазона задается в виде числа N, то здесь удобно использовать цикл for или while. Пример программы с использованием цикла for представлен ниже:

using System;

namespace Prime
{
    class Program
    {
        public static bool IsPrime(int number) 
        { 
            for (int i = 2; i < number; i++) 
            { 
                if (number % i == 0) 
                    return false; 
            } 
            return true; 
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Введите конечное значение диапазона 1...N и нажмите Enter");
            Console.WriteLine("N = "); 
            if ((!int.TryParse(Console.ReadLine(), out int result))||(result<0))
                Console.WriteLine("Число должно быть положительным и целым");
            Console.WriteLine($"Простые числа из диапазона от 1 до {result}");
            int count = 0;
            for (int i = 1; i <= result; i++)
            {
                if (IsPrime(i))
                {
                    Console.Write($"{i} ");
                    count++;
                }
            }
            Console.WriteLine("");
            Console.WriteLine($"Найдено {count} простых чисел из диапазона от 1 до {result}");
        }
    }
}

Строго говоря, число 1 не является ни простым не составным, поэтому его можно было бы исключить из цикла, что мы и сделаем в следующем примере.

Пример определения заданного количества простых чисел

Задача поиска простых чисел может быть сформулирована и по другому, например, так: найти первые N простых чисел. В этом случае нам будет выгодно использовать цикл while:

using System;

namespace Prime
{
    class Program
    {
        public static bool IsPrime(int number) 
        { 
            for (int i = 2; i < number; i++) 
            { 
                if (number % i == 0) 
                    return false; 
            } 
            return true; 
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Введите количество простых чисел которые необходимо найти");
            Console.WriteLine("N = "); 
            if ((!int.TryParse(Console.ReadLine(), out int result))||(result<=0))
                Console.WriteLine("Число должно быть положительным и целым");
            Console.WriteLine($"Первые {result} простых чисел");
            int count = 0; //количество найденных простых чисел
            int number = 1; //очередное число, проверку которого необходимо найти
            int total = 0; //общее количество проверенных чисел
            while (count<result)
            {
                total++;
                number++;
                if (IsPrime(number))
                {
                    Console.Write($"{number} ");
                    count++;
                }
            }
            Console.WriteLine("");
            Console.WriteLine($"Найдено {count} простых чисел. Проверено {total} чисел");
        }
    }
}

Результатом работы программы будет вывод в консоль первых N простых чисел.

Итого

Сегодня мы рассмотрели алгоритм поиска простых чисел и реализовали этот алгоритм в C#. В зависимости от условий задачи, мы использовали различные виды циклов для поиска набора простых чисел.

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

На уроке рассмотрено решение 25 задания ЕГЭ по информатике: дается подробное объяснение и разбор заданий демонстрационных вариантов и досрочных экзаменов

Содержание:

  • Объяснение задания 25 ЕГЭ по информатике
    • Алгоритмизация и программирование
  • Решение 25 заданий ЕГЭ по информатике
    • Делители числа
    • Простые числа
  • Задания прошлых лет для тренировки (до 2021)
    • Задачи с поэлементной обработкой массива
    • Задачи на обработку элементов массива с последующей заменой
    • Задачи на обработку пар элементов массива (два подряд идущих)
    • Задачи на обработку трёх подряд идущих элементов массива (тройки элементов массива)
    • Задачи на поиск максимума, минимума элементов массива и другие
  • Решение 25 заданий ЕГЭ по информатике: более сложные задания

25-е задание: «Программная обработка целочисленной информации»

Уровень сложности

— высокий,

Требуется использование специализированного программного обеспечения

— да,

Максимальный балл

— 2,

Примерное время выполнения

— 20 минут.

  
Проверяемые элементы содержания: Умение создавать собственные программы (10–20 строк) для обработки целочисленной информации

Рекомендации по выполнению:

«В этом задании требуется написать фрагмент программы, реализующий простую обработку целочисленного массива. У экзаменуемых, хорошо освоивших технику программирования, это задание обычно не вызывает серьёзных затруднений, поскольку алгоритм обработки массива не относится к сложным»

Типичные ошибки и рекомендации по их предотвращению:

  • «в цикле происходит выход за границу массива;
  • не инициализируется или неверно инициализируется искомое значение;
  • исходный массив не изменяется;
  • изменяются не все требуемые элементы (например, только первый или последний из них);
  • отсутствует вывод ответа, или ответ выводится не полностью (например, только один элемент массива ввиду пропущенного цикла вывода элементов или операторных скобок);
  • используется переменная, не объявленная в разделе описания переменных;
  • не указано или неверно указано условие завершения цикла»
  • «Часто бывает, что увлекшись написанием решения, экзаменуемый совершает ошибки в простых ситуациях: организация ввода-вывода, описание и инициализация переменных, обработка массива (выход за границу) и т.д. Эти ошибки могут стоить Вам нескольких баллов, старайтесь их не допускать»

    ФГБНУ «Федеральный институт педагогических измерений»

    Алгоритмизация и программирование

    Для решения задания требуется вспомнить темы:

    • Одномерные массивы.
    • Двумерные массивы.

    Решение 25 заданий ЕГЭ по информатике

    Плейлист видеоразборов задания на YouTube:
    Задание демонстрационного варианта 2022 года ФИПИ


    Делители числа

    25_7:

    Напишите программу, которая ищет среди целых чисел, принадлежащих числовому отрезку [126849; 126871], числа, имеющие ровно 4 различных делителя.
    Выведите эти четыре делителя для каждого найденного числа в порядке возрастания.

    ✍ Решение:

      ✎ Решение (неоптимизированный вариант, метод полного перебора):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      
      begin
        var divCount := 4;
        for var n := 126849 to 126871 do
        begin
          var divs := new List<integer>; 
          for var d := 1 to n do
            if n mod d = 0 then begin
              divs.Add(d);      
              if divs.Count > divCount then break;
            end;
          if divs.Count = divCount then
          begin
            divs.Sort();
            Println(divs);
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      
      for n in range(126849,126871+1):
            divs = [] # чистим список делителей
            for d in range(1,n+1): #
              if n % d == 0:
                divs = divs + [d] # добавляем делитель в список
                if len(divs) > 4: break
            if len(divs) == 4:
              print(*divs)
      С++:

      ✎ Решение (оптимизированный вариант):

    • Будем использовать оптимизированный вариант программы, подходящий для «медленных» компьютеров. Для этого перебор делителей для числа n будем выполнять от 2 до √n, округлив его до ближайшего целого числа (не включая точный квадратный корень, если он существует):
    • вместо диапазона делителей [1; число]
      использовать диапазон [1; округл(√n)]
      
    • При переборе делителей будем определять: если делитель – это точный квадратный корень(n), то в список делителей добавлять будем только сам делитель, если нет – то добавляем пару делителей (делитель и n // делитель):
    • Пример:
      число 8 = 2 * 4
      Достаточно рассмотреть цикл от 2 до округл(√8) (=2)
      если 8 делится на 2 и 8/2 не равно 2, то делители: 2 и 4 (8/2)
      
      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      
      begin
        var divCount := 4;
        for var n := 126849 to 126871 do
        begin
          var divs := new List<integer>;
          var d := 1;
          while d * d <= n do  // можно цикл for var d := 1 to round(sqrt(n)) do
          begin
            if n mod d = 0 then begin
              divs.Add(d);      
              if d * d <> n then 
                divs.Add(n div d);
              if divs.Count > divCount then break;
            end;
            d := d+1;
          end;
          if divs.Count = divCount then
          begin
            divs.Sort();
            Println(divs);
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      # import math # для квадратного корня числа (sqrt)
      divCount = 4  # нужное количество делителей
      for n in range(126849,126871 + 1):
        divs = [] # чистим список делителей
        d = 1
        #  вместо while можно цикл for d in range(1,round(math.sqrt(n))):
        while d*d <= n: # перебор делителей
          if n % d == 0:
            divs.append(d) # добавляем делитель в список
            if d != n//d: # если делитель - не точный квадратный корень n
              divs.append(n//d)
            if len(divs) > divCount: break
          d+=1
        if len(divs) == divCount:
          divs.sort()
          print(divs)
      С++:

      ✎ Решение: Генерация списка делителей.
      Общая идея:

    • Для каждого числа указанного диапазона генерируем список делителей.
    • Если длина списка равна четырем, выводим его.
    • PascalABC.net:

      Python:

      for n in range(126849, 126871+1):
        divs = [d for d in range(1, n+1) if n % d == 0] 
        if len(divs) == 4:
          print( *divs )
      С++:

    Ответ:

    1 3 42283 126849
    1 47 2699 126853
    1 5 25373 126865
    1 293 433 126869
    

    25_8:

    Напишите программу, которая ищет среди целых чисел, принадлежащих числовому отрезку [164700; 164752], числа, имеющие ровно 6 различных делителей.
    Выведите эти делители для каждого найденного числа в порядке возрастания.

    ✍ Решение:

      ✎ Решение (оптимизированный вариант):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      
      begin
        var divCount := 6;
        for var n := 164700 to 164752 do
        begin
          var divs := new List<integer>; 
          for var d := 1 to round(sqrt(n)) do
            if n mod d = 0 then begin
              divs.Add(d);      
              if d * d <> n then 
                divs.Add(n div d);
              if divs.Count > divCount then break;
            end;
          if divs.Count = divCount then
          begin
            divs.Sort();
            Println(divs);
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      
      import math # для квадратного корня sqrt
      divCount = 6  # нужное количество делителей
      for n in range(164700, 164752 + 1):
        divs = [] # чистим список делителей
        for d in range(1,round(math.sqrt(n))): # перебор делителей
          if n % d == 0:
            divs.append(d) # добавляем делитель в список
            if d != n//d:
              divs.append(n//d)
            if len(divs) > divCount: break
        if len(divs) == divCount:
          divs.sort()
          print(divs)
      С++:

      ✎ Решение: Генерация списка делителей.
      Общая идея:

    • Для каждого числа указанного диапазона генерируем список делителей.
    • Если длина списка равна четырем, выводим его.
    • PascalABC.net:

      Python:

      for n in range(164700, 164752+1):
          divs = [d for d in range(1, n+1) if n % d == 0] 
          if len(divs) == 6:
              print( *divs )
      С++:

    Ответ:

    1 2 4 41177 82354 164708
    1 3 9 18301 54903 164709
    1 2 4 41179 82358 164716
    1 2 4 41183 82366 164732
    

    25_9:

    Напишите программу, которая ищет среди целых чисел, принадлежащих числовому отрезку [190201; 190230], числа, имеющие ровно 4 различных делителя.
    Выведите эти четыре делителя для каждого найденного числа в порядке убывания.

    ✍ Решение:

      ✎ Решение (неоптимизированный вариант, метод полного перебора):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      begin
        var divs := new integer[4];
        for var n := 190201 to 190230 do
        begin
          var i := 0; // для индекса массива
          for var d := 1 to n do
          begin
            if n mod d = 0 then 
            begin
              if i < 4 then
                divs[i] := d;
              inc(i);
            end;
            if i > 4 then 
              break; 
          end;
          if i = 4 then begin
            println(divs.Reverse())
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      for n in range(190201,190230+1):
            divs = [] # чистим список делителей
            for d in range(1,n+1): #
              if n % d == 0:
                divs = divs + [d] # добавляем делитель в список
                if len(divs) > 4: break
            if len(divs) == 4:
              divs.reverse()
              print(*divs)
      С++:

      ✎ Решение (оптимизированный вариант):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      
      begin
        var divCount := 4;
        for var n := 190201 to 190230 do
        begin
          var divs := new List<integer>; 
          for var d := 1 to round(sqrt(n)) do
            if n mod d = 0 then begin
              divs.Add(d);      
              if d * d <> n then 
                divs.Add(n div d);
              if divs.Count > divCount then break;
            end;
          if divs.Count = divCount then
          begin
            divs.Sort();
            divs.Reverse();
            Println(divs);
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      
      import math # для квадратного корня sqrt
      divCount = 4  # нужное количество делителей
      for n in range(190201, 190230 + 1):
        divs = [] # чистим список делителей
        for d in range(1,round(math.sqrt(n))): # перебор делителей
          if n % d == 0:
            divs.append(d) # добавляем делитель в список
            if d != n//d:
              divs.append(n//d)
            if len(divs) > divCount: break
        if len(divs) == divCount:
          divs.sort()
          divs.reverse()
          print(divs)
      С++:

      ✎ Решение: Генерация списка делителей.
      Общая идея:

    • Для каждого числа указанного диапазона генерируем список делителей.
    • Если длина списка равна четырем, выводим его.
    • PascalABC.net:

      Python:

      for n in range(190201, 190230+1):
          divs = [d for d in range(1, n+1) if n % d == 0] 
          if len(divs) == 4:
              divs.reverse() # реверсируем (по убыванию)
              print( *divs )
      С++:

    Ответ:

    190201 17291 11 1
    190202 95101 2 1
    190214 95107 2 1
    190219 853 223 1
    190222 95111 2 1
    190223 17293 11 1
    190227 63409 3 1
    190229 14633 13 1
    

    Видеоразбор задания:

    📹 YouTube здесь
    📹 Видеорешение на RuTube здесь


    25_10:

    Напишите программу, которая ищет среди целых чисел, принадлежащих числовому отрезку [190201; 190280], числа, имеющие ровно 4 различных ЧЁТНЫХ делителя.
    Выведите эти четыре делителя для каждого найденного числа в порядке убывания.

    ✍ Решение:

      ✎ Решение (неоптимизированный вариант, метод полного перебора):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      begin
        var divs := new integer[4];
        for var n := 190201 to 190280 do
        begin
          var i := 0; // для индекса массива
          for var d := 1 to n do
          begin
            if (n mod d = 0) and (d mod 2 = 0) then 
            begin
              if i < 4 then
                divs[i] := d;
              inc(i);
            end;
            if i > 4 then 
              break; 
          end;
          if i = 4 then begin
            println(divs.Reverse())
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      for n in range(190201,190280+1):
            divs = [] # чистим список делителей
            for d in range(1,n+1): #
              if n % d == 0 and d%2==0:
                divs = divs + [d] # добавляем делитель в список
                if len(divs) > 4: break
            if len(divs) == 4:
              divs.reverse()
              print(*divs)
      С++:

      ✎ Решение: Генерация списка делителей.

      Общая идея:

    • Для каждого числа указанного диапазона генерируем список делителей.
    • Если длина списка равна четырем, выводим его.
    • PascalABC.net:

      Python:

      for n in range(190201, 190280+1):
          divs = [d for d in range(1, n+1) if n % d == 0 and d % 2 == 0] 
          if len(divs) == 4:
              divs.reverse()
              print( *divs )
      С++:

    Ответ:

    190226 838 454 2
    190234 17294 22 2
    190238 2606 146 2
    190252 95126 4 2
    190258 758 502 2
    190274 27182 14 2
    190276 95138 4 2
    

    25_11:

    Напишите программу, которая ищет среди целых чисел, принадлежащих числовому отрезку [394441; 394505], числа, имеющие максимальное количество различных делителей. Если таких чисел несколько, то найдите минимальное из них.
    Выведите количество делителей найденного числа и два наибольших делителя в порядке убывания.

    ✍ Решение:

      ✎ Решение (неоптимизированный вариант, метод полного перебора):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      
      begin
        var max := 0;
        var divsMax := new List<integer>; 
        for var n := 394441 to 394505 do
        begin
          var divs := new List<integer>; 
          for var d := 1 to n do
            if n mod d = 0 then 
              divs.Add(d);      
          if divs.Count > max then 
          begin
            max := divs.Count;
            divsMax := divs;
          end;
        end;
        divsMax.Reverse();
        print(max, divsMax[0], divsMax[1])
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
      maxim = 0  # нужное количество делителей
      divsMax = []
      for n in range(394441, 394505 + 1):
        divs = [] # чистим список делителей
        for d in range(1,n+1): # перебор делителей
          if n % d == 0:
            divs.append(d) # добавляем делитель в список
        if len(divs) > maxim: 
          maxim = len(divs)
          divsMax = divs
      divsMax.reverse()
      print(maxim,divsMax[0],divsMax[1])
      С++:

      ✎ Решение (Генерация списка делителей):

      PascalABC.net:

      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      maxim=0
      divsmax=[]
      for n in range(394441, 394505+1):
          divs = [d for d in range(1, n+1) if n % d == 0] 
          if len(divs) > maxim:
              maxim = len(divs)
              divsmax = divs # сохраняем делители для числа с макс кол-вом дел-ей
      divsmax.reverse()
      print(maxim, divsmax[0], divsmax[1])
      С++:

    Ответ: 48 394450 197225

    Видео

    Простые числа

    25_12:

    Напишите программу, которая ищет среди целых чисел, принадлежащих числовому отрезку [3532000; 3532160], простые числа.
    Выведите все найденные простые числа в порядке убывания, слева от каждого числа выведите его номер по порядку.

    ✍ Решение:

      ✎ Решение (неоптимизированный вариант, метод полного перебора):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      
      begin
        var count := 0;
        for var n := 3532160 downto 3532000 do // цикл с конца 
        begin
          var flag := true; 
          for var d := 2 to n - 1 do // перебор делителей, начиная с двух до n-1
          begin
            if n mod d = 0 then begin // есть делитель помимо единицы и самого n
              flag := false; // число не простое     
              break;
            end;
          end;
          if flag = true then // если число простое
          begin
            inc(count);
            Println(count, n);
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
      count = 0
      for n in range(3532160, 3532000-1, -1): # цикл с конца и с шагом (-1) 
        flag = True
        for d in range(2, n): # перебор делителей, начиная с двух
          if n % d == 0: # есть делитель помимо единицы и самого n
            flag = False # число не простое
            break
        if flag == True: # число простое
          count+=1
          print(count , n)
      С++:

      ✎ Решение (оптимизированный вариант):

      PascalABC.net:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      
      begin
        var count := 0;
        for var n := 3532160 downto 3532000 do // цикл с конца 
        begin
          var flag := true; 
          var d := 2;
          while d * d <= n - 1 do // перебор делителей, начиная с двух
          begin
            if n mod d = 0 then begin // есть делитель помимо единицы и самого n
              flag := false;  // число не простое    
              break;
            end;
            d := d + 1;
          end;
          if flag = true then // если число простое
          begin
            inc(count);
            Println(count, n);
          end;
        end;
      end.
      Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
      count = 0
      for n in range(3532160, 3532000-1, -1): # цикл с конца и с шагом (-1) 
            flag = True
            d = 2
            while d*d <= n-1: # перебор делителей, начиная с двух
                  if n % d == 0: # есть делитель помимо единицы и самого n
                        flag = False # число не простое
                        break
                  d+=1
            if flag == True: # число простое
                  count+=1
                  print(count , n)
      С++:

    Ответ:

    1  3532147
    2  3532121
    3  3532103
    4  3532091
    5  3532049
    6  3532033
    7  3532021
    8  3532019
    9  3532007
    

    Задания прошлых лет для тренировки (до 2021)

    Задачи с поэлементной обработкой массива

    25_1: ЕГЭ по информатике 2017 года (один из вариантов со слов выпускника):

    Дан целочисленный массив из 20 элементов. Элементы массива могут принимать целые значения от 0 до 10 000 включительно. Опишите на естественном языке или на одном из языков программирования алгоритм, позволяющий найти и вывести количество элементов массива НЕ кратных 3.

    Исходные данные объявлены так, как показано ниже. Запрещается использовать переменные, не описанные ниже, но использовать все описанные переменные не обязательно.

    1
    2
    3
    4
    5
    6
    7
    8
    
    const N = 20;
    var i,j,k:integer;
    a:array [1..N] of integer; 
    begin
    for i:=1 to N do 
      readln(a[i]);end.

    ✍ Решение:

    Рассмотрим заданный фрагмент решения:

    • в цикле со счетчиком i запрашиваются значения элементов массива, т.е. формируется массив;
    • из постановки задания видим, что необходимо найти количество чего-то, это значит, что нужно использовать переменную счетчик;
    • объявлены три целочисленных переменных: i, j, k; переменная i использована в первом цикле, значит для счетчика можно взять переменную k;
    • счетчик всегда нужно обнулять, поэтому следующим оператором будет:
    • определим, количество чего нам необходимо считать: количество элементов массива не кратных 3. Кратность можно определить через остаток от деления: если значение элемента массива при делении на 3 в остатке не возвращает 0, значит элемент не кратен трем;
    • остаток при делении в паскале — оператор mod. Поскольку необходимо просмотреть каждый элемент массива, то это нужно делать в цикле for;
    • переменная i уже использована в первом цикле for, значит, для очередного цикла возьмем неиспользованную переменную j:
    • for j:=1 to N do
        if a[j] mod 3 <> 0 then
    • если условие истинно (т.е. нашелся элемент массива, не кратный трем), то увеличиваем счетчик:
    • после цикла остается вывести значение счетчика, т.е. вывести количество элементов массива не кратных 3:

    Результат:

    k:=0;
    for j:=1 to N do
      if a[j] mod 3 <> 0 then
        inc(k);
    writeln(k);

    Смотрите видео с подробным объяснением и разбором данного 25 задания:

    📹 YouTube здесь
    📹 Видеорешение на RuTube здесь


    Задачи на обработку элементов массива с последующей заменой

    25_3: Решение 25 задания ЕГЭ по информатике Демоверсия 2018:

    Дан целочисленный массив из 30 элементов. Элементы массива могут принимать целые значения от 0 до 10000 включительно. Опишите на одном из языков программирования алгоритм, который находит количество элементов массива, больших 100 и при этом кратных 5, а затем заменяет каждый такой элемент на число, равное найденному количеству. Гарантируется, что хотя бы один такой элемент в массиве есть. В качестве результата необходимо вывести измененный массив, каждый элемент массива выводится с новой строчки.

    Например, для массива из шести элементов: 4 115 7 195 25 106
    программа должна вывести числа 4 2 7 2 25 106

    Исходные данные объявлены так, как показано ниже на примерах для некоторых языков программирования. Запрещается использовать переменные, не описанные ниже, но разрешается не использовать некоторые из описанных переменных.

    Паскаль:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    const
    N = 30;
    var
    a: array [1..N] of longint;
    i, j, k: longint;
    begin
    	for i := 1 to N do
    		readln(a[i]);
    	...
    end.

    В качестве ответа Вам необходимо привести фрагмент программы, который должен находиться на месте многоточия. Вы можете записать решение также на другом языке программирования (укажите название и используемую версию языка программирования, например Free Pascal 2.6). В этом случае Вы должны использовать те же самые исходные данные и переменные, какие были предложены в условии.

    Похожие задания для тренировки

    ✍ Решение:

      Решение на языке Паскаль:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      k := 0;
      for i := 1 to N do
      	if (a[i] > 100) and (a[i] mod 5 = 0) then
      		k:=k+1;
      for i := 1 to N do begin
      	if (a[i] > 100) and (a[i] mod 5 = 0) then
      		a[i] := k;
      writeln(a[i])
      end

    25_6:

    Дан массив, содержащий неотрицательные целые числа. Необходимо вывести:

  • максимальный чётный элемент, если количество чётных элементов не меньше, чем нечётных;
  • максимальный нечётный элемент, если количество нечётных эле-ментов больше, чем чётных.
  • Например, для массива из шести элементов: 4 6 12 17 3 8
    ответом будет 12 — наибольшее чётное число, поскольку чётных чисел в этом массиве больше

    Исходные данные объявлены так, как показано ниже. Запрещается использовать переменные, не описанные ниже, но разрешается не использовать некоторые из описанных переменных.

    Python:

    1
    2
    3
    4
    5
    6
    
    # допускается также использовать
    # целочисленные переменные j, k, m
    a = []
    n = 2000 // менять значение n нельзя
    for i in range(0, n):
      a.append(int(input()))

    ✍ Решение:

      Решение на языке Python:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      
      a = []
      n = 2000 // менять значение n нельзя
      for i in range(0, n):
          a.append(int(input()))
      j = 0 
      k = 0 
      m = 0 
      for i in range(0, n):
      	if a[i]%2 == 0:
      		j+=1
      	else:
      		k+=1
      if k>j:
      	j = 0
      	for i in range(0, n):
      		if a[i]>j and a[i] % 2 != 0:
      			j = a[i]
      	print(j)
      else:
      	for i in range(0, n):
      		if a[i]>m and a[i] % 2 == 0:
      			m = a[i]
      	print(m)

    Задачи на обработку пар элементов массива (два подряд идущих)

    25_4:

    Дан целочисленный массив из 40 элементов. Элементы массива могут принимать целые значения от 0 до 10 000 включительно. Опишите на естественном языке или на одном из языков программирования алгоритм, позволяющий найти и вывести количество пар элементов массива, в которых одно из чисел двузначное. В данной задаче под парой подразумевается два подряд идущих элемента массива.

    Например, для массива из семи элементов: 13; 323; 12; 33; 117 — ответ: 4.

    Исходные данные объявлены так, как показано ниже. Запрещается использовать переменные, не описанные ниже, но разрешается не использовать некоторые из описанных переменных.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    const
      N = 40;
    var
      a: array [1..N] of integer;
      i, j, k: integer;
    begin
      for i := 1 to N do 
        readln(a[i]);
      ...
    end.

    ✍ Решение:
     

      1
      2
      3
      4
      5
      
      k := 0;
      for i := 1 to N - 1 do
       if ((a[i] < 100) and (a[i] > 9)) or ((a[i + l] < 100) and (a[i + 1] > 9)) then 
            inc(k);
      writeln(k);

    25_5:

    Дан целочисленный массив из 20 элементов. Элементы массива могут принимать целые значения от -10 000 до 10 000 включительно. Опишите алгоритм, позволяющий найти и вывести количество пар элементов массива, в которых сумма элементов делится на 2, но не делится на 4. В данной задаче под парой подразумевается два подряд идущих элемента массива.

    Исходные данные объявлены так, как показано ниже. Запрещается использовать переменные, не описанные ниже, но разрешается не использовать некоторые из описанных переменных.

    Python:

    1
    2
    3
    4
    5
    6
    7
    
    #  допускается также использовать
    #  две целочисленные переменные
    #  j и k
    a = []
    n = 20
    for i in range(0, n):
      a.append(int(input()))

    ✍ Решение:

      Проанализируем данный фрагмент кода на языке Python:

    • В первой строчке кода объявляется список а. Дальше, идет объявление переменной n = 20, она отвечает за размер массива.
    • При решении такого рода задач, необходимо помнить, что массив в Python — это список и это динамический тип данных. Кроме того, нумерация элементов массива начинается с 0.

    • Ниже мы видим инициализацию списка а. Мы должны дописать код дальнейшей программы, который последует после заполнения списка пользователем.
    • Итак, по условию мы должны находить пары элементов, сумма которых делится на 2, но не делится на 4, причем парами считаются соседние элементы, например: a[0] и a[1], a[1] и a[2].
    • Мы можем узнать, делится ли данный элемент на число, если остаток от деления на него равен 0, и не делится — в противном случае. Тогда сумма соседних элементов при делении на 2 должна давать остаток 0, а при делении на 4 наоборот — отличный от 0.
    • Введем цикл, который будет перебирать все элементы массива, считать сумму соседей и проверять истинность условия.
    • for i in range(0, n-1):
          j = a[i] + a[i+1]
          if j%2 == 0 and j%4 != 0:

      Так как мы рассматриваем элемент a[i + 1], значит, цикл должен работать до n — 1, чтобы не выйти за границы диапазона массива.

    • Когда мы определились с условием, за счетчик возьмем переменную k, которую допустимо брать исходя из комментариев к программе.
    • ...
       if j%2 == 0 and j%4 != 0:
              k+=1
    • Мы добавили допустимую переменную j, чтобы условный оператор выглядел компактнее.
    • Однако задача еще не решена. Во-первых, мы должны до цикла инициализировать счетчик k = 0. Так как иначе Python выдаст ошибку.
    • Дело в том, что мы пытаемся присвоить переменной k его же значение, но на 1 больше, но интерпретатор «не встречал» раньше переменной k, из-за чего возникает ошибка.

    • Кроме того, добавим вывод результата после цикла.
    • Таким образом, правильный вариант с учетом доработок:
    • a = []
      n = 20
      for i in range(0, n):
        a.append(int(input()))
      k = 0
      for i in range(0, n - 1):
          j = a[i] + a[i + 1]
          if j%2 == 0 and j%4 != 0:
              k += 1
      print(k)

    Задачи на обработку трёх подряд идущих элементов массива (тройки элементов массива)

    25_2:

    Дан целочисленный массив из 40 элементов. Элементы массива могут принимать целые значения от 0 до 10 000 включительно. Опишите на естественном языке или на одном из языков программирования алгоритм, позволяющий найти и вывести количество троек элементов массива, состоящих из равных между собой чисел. В данной задаче под тройкой подразумевается три подряд идущих элемента массива.

    Например, для массива из семи элементов: 2; 2; 2; 4; 4; 4; 4 — ответ: 3.

    Исходные данные объявлены так, как показано ниже. Запрещается использовать переменные, не описанные ниже, но разрешается не использовать некоторые из описанных переменных.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    const
      N=40;
    var
      a: array[1..N] of integer;
      i, j, k:integer;
    begin
      for i:=1 to N do
        readln(a[i]);
      ...
    end.

    ✍ Решение:

    • из постановки задания видим, что необходимо искать количество чего-то, это значит, что нужно использовать переменную счетчик; возьмем для нее объявленную переменную k;
    • счетчик всегда нужно сначала обнулять, поэтому следующим оператором будет:
    • определим, количество чего нам необходимо считать: количество троек элементов массива, состоящих из равных между собой чисел. Т.е. необходимо сравнивать между собой каждые три подряд идущих элемента массива, например так:
    • if (a[i]=a[i+1]) and (a[i]=a[i+2]) then
          inc(k);
    • inc(k) — оператор, увеличивающий счетчик k на единицу;
    • условие необходимо выполнять в цикле, так как нужно проверить все элементы массива; цикл со счетчиком необходимо организовать от 1 до N-2, в противном случае индексы элементов a[i+2] выйдут за границы диапазона массива (например, при i = 40, получим … a[40+2], а 42-го элемента массива не существует, поэтому цикл надо делать до i = 38, т.е. N-2).

    Результат:

    for i:=1 to N-2 do
        if (a[i]=a[i+1]) and (a[i]=a[i+2]) then
          inc(k);
    writeln(k);

    Более подробное объяснение предлагаем посмотреть на видео:

    📹 YouTube здесь
    📹 Видеорешение на RuTube здесь


    Задачи на поиск максимума, минимума элементов массива и другие

    Понравилась статья? Поделить с друзьями:
  • Как найти глубину ящика
  • Где как в компьютере найти буфер обмена
  • Как молодому бухгалтеру найти работу
  • Как найти повод встретиться с мужчиной
  • Как найти пропавшее фото в компьютере