Задача:
Найти наименьшее общее кратное для всех элементов массива — минимальное число, которое делится на все элементы массива без остатка. Также, найти НОД всех элементов массива.
Решение:
Вот тут приведены алгоритмы расчета НОК и НОД для двух чисел. Ясно, что наиболее эффективный алгоритм расчета НОК двух чисел — это произведение чисел поделить на их НОД. По содержимому статьи ясно что НОК(а1, а2, а3, ... аN)
равен НОК(НОК(НОК(А1, А2), А3)..., АN)
. Таким образом, для расчета НОК массива чисел надо многократно расчитывать НОД двух чисел, реализация этой функции на С++ взята тут.
Реализация на Си (функции чуть-чуть изменены, так как добавлена самописная функция swap):
#include <stdio.h> #include <stdlib.h> void read_array(int n, int** values) { for (int i = 0; i < n; ++i) { printf("values[%d] = ", i); scanf("%d", &((*values)[i])); } } void print_array(int n, int* values) { for (int i = 0; i < n; ++i) { printf("values[%d] = %dn", i, values[i]); } } void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int gcd(int a, int b) { if (a < b) { swap(&a, &b); } while (a % b != 0) { a = a % b; swap(&a, &b); } return b; } int gcd_n(int n, int* values) { if (n == 0) return -1; if (n == 1) return values[0]; int gcd_value = gcd(values[0], values[1]); for (int i = 2; i < n; ++i) { gcd_value = gcd(gcd_value, values[i]); } return gcd_value; } int lcm(int a, int b) { return (a*b)/gcd(a, b); } int lcm_n(int n, int* values) { if (n == 0) return -1; if (n == 1) return values[0]; int lcm_value = lcm(values[0], values[1]); for (int i = 2; i < n; ++i) { lcm_value = lcm(lcm_value, values[i]); } return lcm_value; } int main() { int n; int *values; printf("n: "); scanf("%d", &n); values = malloc(sizeof(int) * n); read_array(n, &values); printf("lcm: %d", lcm_n(n, values)); free(values); return 0; }
Алгоритм Евклида
Для начала разберемся, что это и как это работает. Алгоритм Евклида позволяет найти нам наибольший общий делитель чисел. Как это работает:
Пусть a = 18, b = 30.
Цикл: a!=0 and b!=0
Если a > b, то a = a % b, если меньше, то b = b % a, таким образом мы сначала находим остаток деления, а потом повторяем действия. У нас a < b, значит, ищем остаток деления b % a (30 % 18) = 12, присваиваем b = 12, повторяем цикл но теперь у нас уже a > b(b = 12)
значит выполняем a % b (18 % 12) = 6? снова переходим к циклу, теперь снова b > a, значит выполняем b % a (30 % 6), остаток от деления 0, на этом мы прекращаем наш цикл и узнаем, что наибольший общий делитель 18 и 30 = 6. и выводим a + b (b = 0, a = 6).
Python
#!/usr/bin/env python
a = 18
b = 30
while a!=0 and b!=0:
if a > b:
a = a % b
else:
b = b % a
print (a+b)
Perl:
sub nod
{
return $_[0] != 0 ? nod ( ( $_[1] % $_[0] ), $_[0] ) : $_[1];
}
C:
int gcd(int a, int b) {
int c;
while (b) {
c = a % b;
a = b;
b = c;
}
return abs(a);
}
Pascal:
function nod( a, b: longint): longint;
begin
while (a <> 0) and (b <> 0) do
if a >= b then
a:= a mod b
else
b:= b mod a;
nod:= a + b;
end;
Java:
public class GCD {
public static int gcd(int a,int b) {
while (b !=0) {
int tmp = a%b;
a = b;
b = tmp;
}
return a;
}
}
C#:
int gcd(int a, int b)
{
while (b != 0)
b = a % (a = b);
return a;
}
19 / 19 / 4 Регистрация: 18.02.2011 Сообщений: 292 |
|
1 |
|
Нахождение НОД14.10.2011, 21:50. Показов 51144. Ответов 13
Здравствуйте, мне надо найти НОД чисел. Как это реализовать на языке C++ ?
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
14.10.2011, 21:50 |
13 |
2554 / 1319 / 178 Регистрация: 09.05.2011 Сообщений: 3,086 Записей в блоге: 1 |
|
14.10.2011, 21:53 |
2 |
0 |
19 / 19 / 4 Регистрация: 18.02.2011 Сообщений: 292 |
|
14.10.2011, 22:13 [ТС] |
3 |
я пробую, но у меня ничего не выводит на экран!
0 |
447 / 210 / 21 Регистрация: 07.10.2011 Сообщений: 462 |
|
14.10.2011, 22:25 |
4 |
PaZL, ну тогда код в студию. Или мы должны угадать, почему оно не работает?
1 |
4265 / 2239 / 203 Регистрация: 26.08.2011 Сообщений: 3,802 Записей в блоге: 5 |
|
15.10.2011, 09:38 |
5 |
0 |
156185 19 / 19 / 4 Регистрация: 18.02.2011 Сообщений: 292 |
||||
15.10.2011, 12:45 [ТС] |
6 |
|||
мне пишет Код c:mingwbin..libgccmingw324.5.2......libmingw32.a(main.o):main.c|| undefined reference to `WinMain@16'|
0 |
447 / 210 / 21 Регистрация: 07.10.2011 Сообщений: 462 |
|
15.10.2011, 13:20 |
7 |
PaZL, это мы и так поняли, полный код нужен и другие сведения. Где ваша функция main()? Какой у вас компилятор и тип проекта Если б была Visual Studio, то на такую ошибку я б сказала, что у вас проект не того типа создан
0 |
Higher 1953 / 1219 / 120 Регистрация: 02.05.2010 Сообщений: 2,925 Записей в блоге: 2 |
|
15.10.2011, 13:23 |
8 |
PaZL, это мы и так поняли, полный код нужен и другие сведения. Где ваша функция main()? Какой у вас компилятор и тип проекта Если б была Visual Studio, то на такую ошибку я б сказала, что у вас проект не того типа создан Есть сильное подозрение, что это и есть полный код =)
0 |
19 / 19 / 4 Регистрация: 18.02.2011 Сообщений: 292 |
|
15.10.2011, 13:26 [ТС] |
9 |
aeshes, у меня компилятор MinGW, IDE: CodeBlocks. Я новичок в C++, помогите составить полный код, чтобы выводила результат.
0 |
aeshes 447 / 210 / 21 Регистрация: 07.10.2011 Сообщений: 462 |
||||
15.10.2011, 13:26 |
10 |
|||
Не по теме: diagon, я тоже подозревала, но хочется верить в хорошее в людях)) PaZL, в приведенных примерах есть только реализация метода поиска НОД. Чтобы посмотреть, как он работает, вам надо помимо этого создать еще функцию int main(), подключить нужные библиотеки, ввести 2 числа и вызвать для них функцию примерно так
4 |
В вечном поиске… 275 / 235 / 30 Регистрация: 05.04.2011 Сообщений: 645 |
|
15.10.2011, 13:28 |
11 |
PaZL, а книжку открыть не вариант?
0 |
19 / 19 / 4 Регистрация: 18.02.2011 Сообщений: 292 |
|
15.10.2011, 13:50 [ТС] |
12 |
aeshes, спасибо все получилось!
0 |
0 / 0 / 0 Регистрация: 27.07.2016 Сообщений: 1 |
|
08.01.2017, 18:54 |
13 |
Ребят, объясните чайнику как работает return a | b; Я понимаю, что оно возвращает не равное 0 значение, но что это за выражение такое? Что это вообще за |. Впервые вижу.
0 |
Падаван С++ 447 / 261 / 89 Регистрация: 11.11.2014 Сообщений: 916 |
|
08.01.2017, 19:40 |
14 |
Fozek, битовое или, почитайте про битовые операции
1 |
Алгоритм Евклида – нахождение наибольшего общего делителя
Алгоритм Евклида – это алгоритм нахождения наибольшего общего делителя (НОД) пары целых чисел.
Наибольший общий делитель (НОД) – это число, которое делит без остатка два числа и делится само без остатка на любой другой делитель данных двух чисел. Проще говоря, это самое большое число, на которое можно без остатка разделить два числа, для которых ищется НОД.
Решение задачи на языке программирования Python
Алгоритм нахождения НОД делением
- Большее число делим на меньшее.
- Если делится без остатка, то меньшее число и есть НОД (следует выйти из цикла).
- Если есть остаток, то большее число заменяем на остаток от деления.
- Переходим к пункту 1.
Пример:
Найти НОД для 30 и 18.
30 / 18 = 1 (остаток 12)
18 / 12 = 1 (остаток 6)
12 / 6 = 2 (остаток 0)
Конец: НОД – это делитель 6.
НОД (30, 18) = 6
a = int(input()) b = int(input()) while a != 0 and b != 0: if a > b: a = a % b else: b = b % a print(a + b)
В цикле в переменную a или b записывается остаток от деления. Цикл завершается, когда хотя бы одна из переменных равна нулю. Это значит, что другая содержит НОД. Однако какая именно, мы не знаем. Поэтому для определения НОД находим сумму этих переменных. Поскольку в одной из переменных ноль, он не оказывает влияние на результат.
Если условием завершения цикла является равенство хотя бы одной из переменных нулю (a == 0 or b == 0
), то условием продолжения его работы является обратное этому условие – обе переменные должны иметь отличные от нуля значения (a != 0 and b != 0
).
Для того, чтобы вышеприведенная программа могла обрабатывать отрицательные числа, в логическом выражении при if
должны сравниваться модули значений переменных: if abs(a) > abs(b):
. Иначе большим числом может оказаться меньшее по модулю. В этом случае интерпретатор Питона в качестве остатка от деления выдает вещественное число. В результате это приводит к зацикливанию, так как низвести переменные до нуля становится как минимум маловероятным.
Алгоритм нахождения НОД вычитанием
- Из большего числа вычитаем меньшее.
- Если получается 0, значит, числа равны друг другу и являются НОД (следует выйти из цикла).
- Если результат вычитания не равен 0, то большее число заменяем на результат вычитания.
- Переходим к пункту 1.
Пример:
Найти НОД для 30 и 18.
30 – 18 = 12
18 – 12 = 6
12 – 6 = 6
6 – 6 = 0
Конец: НОД – это уменьшаемое или вычитаемое.
НОД (30, 18) = 6
a = int(input()) b = int(input()) while a != b: if a > b: a = a - b else: b = b - a print(a)
Функция, вычисляющая НОД
def gcd(m, n): while m != n: if m > n: m = m - n else: n = n - m return n a = int(input()) b = int(input()) print(gcd(a, b))
Функция gcd
модуля math
В модуле math
языка программирования Python есть функция gcd
, вычисляющая наибольший общий делитель двух чисел.
>>> import math >>> math.gcd(30, 18) 6
Больше задач в PDF
Наибольшим общим делителем (НОД) для двух целых чисел m и n называется наибольшее число, на которое делятся числа m и n. Наибольший общий делитель существует и однозначно определён, если хотя бы одно из чисел m или n не равно нулю.
Алгоритм был придуман Евклидом в Древней Греции более 2000 лет назад и основан на следующем правиле.
Для любых целых чисел x, y > 0 выполняется равенство
НОД (x, y) = НОД (x % y, y)
Любое число, которое делит оба числа x и y, делит также и x — y, поэтому
НОД (x, y) ≤ НОД (x — y, y).
Аналогично, любое число, которое делит оба числа x − y и y, делит также и их сумму x, поэтому
НОД (x, y) ≥ НОД (x — y, y).
Требуемое равенство получается последовательным вычитанием y из x.
Идея алгоритма отыскания наибольшего общего делителя заключается в том, чтобы отнимать от большего меньшее, пока числа не станут равны. Полученное число и является наибольшим общим делителем.
Например, необходимо определить наибольший общий делитель чисел 50 и 20.
- находим 50-20=30. Из трех чисел 50, 20, 30 отбрасываем наибольшее.
- находим 30-20=10. Из трех чисел 30, 20, 10 отбрасываем наибольшее.
- находим 20-10 = 10. Из трех чисел 20, 10, 10 отбрасываем наибольшее.
- 10=10, значит это число является наибольшим общим делителем исходных.
Реализацию указанного алгоритма удобно произвести с использованием рекурсивной процедуры.
Реализация на С++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
using namespace std;
// Функция нахождения НОД
int NOD(int n1, int n2)
{
int div;
if (n1 == n2) // если числа равны, НОД найден
return n1;
int d = n1 – n2; // Находим разность чисел
if (d < 0) // если разность отрицательная,
{
d = -d; // меняем знак
div = NOD(n1, d); // вызываем функцию NOD() для двух наименьших чисел
}
else // если разность n1-n2 положительная
{
div = NOD(n2, d); // вызываем функцию NOD() для двух наименьших чисел
}
return div;
}
int main()
{
int n1, n2;
cout << “n1=”;
cin >> n1;
cout << “n2=”;
cin >> n2;
cout << NOD(n1, n2);
cin.get(); cin.get(); return 0;
}
Результат выполнения
Назад: Алгоритмизация