Алгоритмы решения прикладных задач, 1-й семестр, 2-я практика
Практика затрагивает алгоритмы нахождения наибольшего общего делителя (метод деления, метод вычитания), алгоритмы поиска простых чисел (решето Эратосфена, решето Сундарама, тест Люка-Лемера), алгоритмы факторизации чисел (алгоритм Ферма), алгоритмы генерации псевдослучайных чисел (числа фон Неймана).
Задания
Задание 1
Написать программу для поиска наибольшего общего делителя (числа вводятся с клавиатуры после запуска программы): Нечетные варианты: наибольший делитель трех чисел методом деления (для поиска остатка отделения в языке C++ используется операция %) Четные варианты: наибольший общий делитель четырех чисел метолом вычитания
// Функция для нахождения НОД двух чисел (метод деления)
int gcdDivision(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// Функция для нахождения НОД трех чисел
int gcdOfThreeNumbers(int x, int y, int z) {
return gcdDivision(gcdDivision(x, y), z);
}
// Функция для нахождения НОД двух чисел методом вычитания
int gcdSubtraction(int a, int b) {
while (a != b) {
if (a > b) {
a -= b;
} else {
b -= a;
}
}
return a; // или b, так как a == b
}
// Функция для нахождения НОД четырех чисел
int gcdOfFourNumbers(int w, int x, int y, int z) {
return gcdSubtraction(gcdSubtraction(gcdSubtraction(w, x), y), z);
}
Задание 2
Написать программу для факторизации заданного с клавиатуры числа методом простого перебора (указать простые множители и их кратность). Для анализа числа на простоту использовать решето Эратосфена
#include <vector>
#include <map>
#include "sieveoferatosthenes.cpp"
// Функция для факторизации числа (метод простого перебора)
std::map<int, int> factorize(int number) {
std::map<int, int> factors;
std::vector<int> primes = sieveOfEratosthenes(number);
for (int prime : primes) {
if (prime * prime > number) break;
while (number % prime == 0) {
factors[prime]++;
number /= prime;
}
}
if (number > 1) {
factors[number]++;
}
return factors;
}
Задание 3
Написать программу для факторизации заданного с клавиатуры нечетного числа методом Ферма (указать простые множители и их кратность). Для анализа числа на простоту использовать решето Эратосфена
#include <iostream>
#include <cmath>
bool isPerfectSquare(int num) {
int s = static_cast<int>(sqrt(num));
return (s * s == num);
}
int main() {
long long n;
std::cout << "Введите n (произведение двух простых чисел p и q): ";
std::cin >> n;
long long m = static_cast<long long>(sqrt(n));
long long x = 1;
while (true) {
long long q = (m + x) * (m + x) - n;
if (isPerfectSquare(q)) {
long long k = static_cast<long long>(sqrt(q));
long long p = m + x - k;
long long q_value = m + x + k;
std::cout << "Найдены p и q: p = " << p << ", q = " << q_value << std::endl;
break;
}
x++;
}
return 0;
}
Задание 4
Написать программу для проверки на простоту числа Мерсенна с использование теста Люка-Лемера. С клавиатуры вводится номер числа Мерсенна
#include <iostream>
#include <cmath>
// Тест Люка-Лемера для проверки простоты числа Мерсенна
bool lucasLehmerTest(long long p) {
if (p == 2) return true; // M_2 = 3, простое число
// Вычисляем M_p = 2^p - 1
long long M_p = (1LL << p) - 1; // 1LL << p эквивалентно 2^p
// Начальное значение s
long long s = 4;
// Выполняем тест
for (long long i = 3; i <= p; ++i) {
s = (s * s - 2) % M_p; // s = s^2 - 2
}
// Если s % M_p == 0, то M_p простое
return s == 0;
}
Задание 5
Написать программу для генерации последовательности из 10 пятизначных чисел фон Неймана
#include <vector>
std::vector<int> vonNeumannSequence(unsigned long int n) {
std::vector<int> sequence;
for (int i = 0; i < 10; i++)
{
retry:
n = n*n;
n = (n / 100)%100000;
if (n < 10000 || n >= 1000000)
{
goto retry;
}
sequence.push_back(n);
}
return sequence;
}
Задание 6
Написать программу для поиска простых чисел по алгоритму «Решето Сундарама»
#include <iostream>
void Sundaram(bool A[], int N)
{
int i, j;
for (i = 1; i <= N; i++) A[i] = true;
i = 1; j = 1;
while ((2 * i * j + i + j) <= N)
{
while (j <= (N - i) / (2 * i + 1))
{
A[2 * i * j + i + j] = false;
j++;
}
i++;
j = i;
}
for (i = 1; i <= N; i++) {
if (A[i]) std::cout << 2 * i + 1 << " ";
}
}