Как найти наибольший общий делитель программирование

Алгоритм Евклида – нахождение наибольшего общего делителя

Алгоритм Евклида – это алгоритм нахождения наибольшего общего делителя (НОД) пары целых чисел.

Наибольший общий делитель (НОД) – это число, которое делит без остатка два числа и делится само без остатка на любой другой делитель данных двух чисел. Проще говоря, это самое большое число, на которое можно без остатка разделить два числа, для которых ищется НОД.

Решение задачи на языке программирования Python

Алгоритм нахождения НОД делением

  1. Большее число делим на меньшее.
  2. Если делится без остатка, то меньшее число и есть НОД (следует выйти из цикла).
  3. Если есть остаток, то большее число заменяем на остаток от деления.
  4. Переходим к пункту 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):. Иначе большим числом может оказаться меньшее по модулю. В этом случае интерпретатор Питона в качестве остатка от деления выдает вещественное число. В результате это приводит к зацикливанию, так как низвести переменные до нуля становится как минимум маловероятным.

Алгоритм нахождения НОД вычитанием

  1. Из большего числа вычитаем меньшее.
  2. Если получается 0, значит, числа равны друг другу и являются НОД (следует выйти из цикла).
  3. Если результат вычитания не равен 0, то большее число заменяем на результат вычитания.
  4. Переходим к пункту 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

Алгоритм Евклида (или алгоритм Евклида) — это метод эффективного нахождения наибольшего общего делителя (НОД) двух чисел. НОД двух целых чисел, X а также Y, является наибольшим числом, которое делит оба X а также Y не оставляя остатка.

Например,

Euclid(30, 50) = 10

 
Euclid(2740, 1760) = 20

Потренируйтесь в этой проблеме

The Евклидов алгоритм основывается на том принципе, что наибольший общий делитель двух чисел не изменится, если большее число заменить его разностью с меньшим числом.

Например, 21 — это НОД 252 и 105 (252 = 21 × 12 а также 105 = 21 × 5), а то же число 21 также является НОД 105 и 147 (147 = 252 - 105).

 
Поскольку эта замена уменьшает большее из двух чисел, повторение этого процесса дает последовательно меньшие пары чисел, пока два числа не станут равными. Когда это происходит, они являются GCD исходных двух чисел.

Следующая программа на C демонстрирует это:

C

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 <stdio.h>

// Итерационная функция для вычисления НОД двух чисел

// с использованием алгоритма Евклида (базовая версия)

int euclid(int a, int b)

{

    // делаем до тех пор, пока два числа не станут равными

    while (a != b)

    {

        // заменить большее число на его разность с меньшим числом

        if (a > b) {

            a = a b;

        }

        else {

            b = b a;

        }

    }

    return a;        // или `b` (поскольку оба равны)

}

int main()

{

    int a = 30;

    int b = 50;

    printf(“Euclid(%d, %d) = %d”, a, b, euclid(a, b));

    return 0;

}

Скачать  Выполнить код

результат:

Euclid(30, 50) = 10

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

 
Более эффективная версия алгоритма заменяет большее из двух чисел его остатком при делении на меньшее. Алгоритм останавливается при достижении нулевого остатка, и теперь алгоритм никогда не требует больше шагов, чем пятикратное количество цифр (по основанию 10) меньшего целого числа.

Итеративную и рекурсивную реализацию можно увидеть ниже на C:

Итеративный

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

31

32

33

#include <stdio.h>

// Итерационная функция для вычисления НОД двух чисел

// используя алгоритм Евклида

int euclid(int a, int b)

{

    int q, r;

    // цикл до остатка 0

    while (b > 0)

    {

        q = a / b;      // частное

        r = a q * b;  // остаток

        // или мы можем просто использовать `a % b` для вычисления `r`

        // `a` становится `b`, а `b` становится `r` (`a % b`)

        a = b;

        b = r;

    }

    return a;

}

int main()

{

    int a = 2740;

    int b = 1760;

    printf(“Euclid(%d, %d) = %d”, a, b, euclid(a, b));

    return 0;

}

Скачать  Выполнить код

результат:

Euclid(2740, 1760) = 20

Рекурсивный

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

#include <stdio.h>

// Рекурсивная функция для вычисления НОД двух чисел

// используя алгоритм Евклида

int euclid(int a, int b)

{

    // если остаток равен 0, возвращаем второе число

    if (b == 0) {

        return a;

    }

    int q = a / b;      // частное

    int r = a q * b;  // остаток

    // или мы можем просто использовать `a % b` для вычисления `r`

    // `a` становится `b`, а `b` становится `r` (`a % b`)

    return euclid(b, r);

}

int main()

{

    int a = 2740;

    int b = 1760;

    printf(“Euclid(%d, %d) = %d”, a, b, euclid(a, b));

    return 0;

}

Скачать  Выполнить код

результат:

Euclid(2740, 1760) = 20

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

C

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

#include <stdio.h>

#include <stdlib.h>

// Итерационная функция для вычисления НОД двух чисел

// используя алгоритм Евклида

int euclid(int a, int b)

{

    int r;

    // цикл до остатка 0

    while (b > 0)

    {

        // вычисляем остаток

        r = a % b;

        // `a` становится `b`, а `b` становится `r`

        a = b;

        b = r;

    }

    return a;

}

int main()

{

    FILE *in, *out;

    in = fopen(“input.txt”, “r”);

    if (in == NULL)

    {

        printf(“Cannot open the source file.n”);

        exit(1);

    }

    out = fopen(“output.txt”, “w”);

    if (out == NULL)

    {

        printf(“Cannot open the destination file.n”);

        exit(1);

    }

    int a, b;

    char ch;

    // делаем до тех пор, пока не будет достигнут конец файла

    while (!feof(in))

    {

        // прочитать следующую пару входных данных из файла

        fscanf(in, “%d %d”, &a, &b);

        // вычисляем gcd и печатаем в выходной файл

        fprintf(out, “Euclid(%d, %d) = %dn”, a, b, euclid(a, b));

        // переходим к следующей строке

        ch = getc(in);

    }

    // закрыть входной и выходной файловый поток

    fclose(out);

    fclose(in);

    return 0;

}

 
результат:


input.txt
2740 1760
6 4

 
output.txt
Euclid(2740, 1760) = 20
Euclid(6, 4) = 2

 
Также см:

Расширенный алгоритм Евклида — реализация на C, C++, Java и Python

НОД – это математический термин, обозначающий наибольший общий делитель, который может идеально разделить два числа. НОД также известен как наибольший общий фактор(HCF).

Например, HCF / GCD двух чисел 54 и 24 равен 6. Поскольку 6 – это наибольший общий делитель, который полностью делит 54 и 24.

Разберемся как найти НОД двух чисел в Python. НОД двух чисел в Python

НОД с использованием функции gcd()

gcd() в python – это встроенная функция, предлагаемая математическим модулем для поиска наибольшего общего делителя двух чисел.

Синтаксис:

 
gcd(a, b) 

Где a и b – два целых числа, которые передаются в качестве аргумента функции gcd().

Давайте создадим программу для печати НОД двух чисел, используя встроенную функцию math.gcd() в python.

math_fun.py

 
# create a program to print the gcd of two number in python using the math.gcd() function. 
import math 
print(" GCD of two number 0 and 0 is ", math.gcd(0, 0)) #math.gcd(a, b), a and b are the two integer number 
print(" GCD of two number 0 and 48 is ", math.gcd(0, 48)) 
a = 60 # assign the number to variable a 
b = 48 # assign the number to variable b 
print(" GCD of two number 60 and 48 is ", math.gcd(a, b)) # pass the variable a and b to math.gcd() function. 
print(" GCD of two number 48 and -12 is ", math.gcd(48, -12)) # pass the integer number 
print(" GCD of two number -24 and -18 is ", math.gcd(-24, -18)) 
print(" GCD of two number -60 and 48 is ", math.gcd(-60, 48)) 

Выход:

Выход

В приведенном выше примере функция math.gcd() генерирует НОД двух заданных чисел. В функции gcd() a и b передаются в качестве аргумента, который возвращает наибольший общий делитель двух целых чисел, полностью разделяя числа.

НОД с использованием рекурсии

Рекурсия – это функция, потребляющая память, определенная в Python, которая вызывает себя через самореферентное выражение. Это означает, что функция будет постоянно вызывать и повторять себя до тех пор, пока не будет выполнено определенное условие для возврата наибольшего общего делителя числа.

Псевдокод алгоритма

Шаг 1: Возьмите два входа, x и y, от пользователя.

Шаг 2: Передайте входной номер в качестве аргумента рекурсивной функции.

Шаг 3: Если второе число равно нулю(0), возвращается первое число.

Шаг 4: В противном случае он рекурсивно вызывает функцию со вторым числом в качестве аргумента, пока не получит остаток, который делит второе число на первое число.

Шаг 5: Вызовите или назначьте gcd_fun() переменной.

Шаг 6: Отобразите НОД двух чисел.

Шаг 7: Выйдите из программы.

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

gcdRecur.py

 
# write a program to understand the GCD of two number in python using the recursion. 
def gcd_fun(x, y): 
    if(y == 0): # it divide every number 
        return x  # return x 
    else: 
        return gcd_fun(y, x % y) 
x =int(input("Enter the first number: ")) # take first no.  
y =int(input("Enter the second number: ")) # take second no.  
num = gcd_fun(x, y) # call the gcd_fun() to find the result 
print("GCD of two number is: ") 
print(num) # call num 

Выход:

Нахождение НОД двух чисел с помощью рекурсии

Нахождение НОД с помощью цикла

Давайте создадим программу для нахождения НОД двух чисел в Python с помощью циклов.

gcdFile.py

 
def GCD_Loop( a, b): 
    if a > b:  # define the if condition 
        temp = b 
    else: 
        temp = a 
    for i in range(1, temp + 1): 
        if(( a % i == 0) and(b % i == 0 )): 
            gcd = i 
    return gcd 
x = int(input(" Enter the first number: ") ) # take first no.  
y =int(input(" Enter the second number: ")) # take second no.  
num = GCD_Loop(x, y) # call the gcd_fun() to find the result 
print("GCD of two number is: ") 
print(num) # call num 

Выход:

Нахождение НОД с помощью цикла

Как мы видим в приведенной выше программе, мы берем два значения в качестве входных и передаем эти числа в функцию GCD_Loop(), чтобы вернуть GCD.

Алгоритм Евклида

Алгоритм Евклида – эффективный метод нахождения наибольшего общего делителя двух чисел. Это самый старый алгоритм, который делит большее число на меньшее и берет остаток. Опять же, он делит меньшее число от остатка, и этот алгоритм непрерывно делит число, пока остаток не станет 0.

Например, предположим, что мы хотим вычислить HCF двух чисел, 60 и 48. Затем мы делим 60 на 48; он возвращает остаток 12. Теперь мы снова делим число 24 на 12, а затем он возвращает остаток 0. Таким образом, мы получаем HCF равным 12.

Псевдокод алгоритма Евклида

Шаг 1: Есть два целых числа, например a и b.

Шаг 2: Если a = 0, то НОД(a, b) равен b.

Шаг 3: Если b = 0, НОД(a, b) равен a.

Шаг 4: Найти mod b.

Шаг 5: Предположим, что a = b и b = R.

Шаг 6: Повторяйте шаги 4 и 3, пока mod b не станет равным или большим 0.

Шаг 7: GCD = b и затем распечатайте результат.

Шаг 8: Остановите программу.

Найдем HCF или GCD двух чисел, используя алгоритм Евклида в python.

Euclid.py

 
# Create a program to find the GCD of two number in python using the Euclid's Algorithm. 
def find_hcf(a,b): 
    while(b): 
        a, a = b, a % b 
        return a 
a = int(input(" Enter the first number: ") ) # take first no.  
b = int(input(" Enter the second number: ")) # take second no.  
num = find_hcf(a, b) # call the find_hcf() to get the result 
print("  The HCF of two number a and b is ") 
print(num) # call num 

Выход:

Алгоритм Евклида для НОД

Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.

Наибольший общий делитель

Как несложно догадаться, наибольший общий делитель (англ. greatest
common divisor) двух целых чисел – наибольшее число, на которое делится
каждое из них. Например:

[gcd(15, 20) = 5]

[gcd(12, 30) = 6]

Сразу заметим важное свойство:

[gcd(a, b) = gcd(b, a)]

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

Алгоритм Евклида

Алгоритм Евклида – один из первых алгоритмов в истории, использовался
ещё в Древней Греции, и дошёл до наших дней. В изначальном виде он назывался
“взаимным вычитанием”, так как заключался в поочерёдном вычитании меньшего
числа из большего, пока одно из них не станет равным 0. Сегодня чаще всего
вместо вычитания используется взятие остатка от деления, но суть алгоритма
сохранилась.

Алгоритм заключается в построении ряда чисел следующего вида ((a > b)):

[a, b, r_1, r_2, ldots, r_n]

Где каждое последующее число является остатком от деления предпредыдущего
на предыдущее:

[r_1 = a bmod b \
r_2 = b bmod r_1 \
ldots \
r_n = r_{n – 2} bmod r_{n – 1}]

Ряд заканчивается, когда остаток от деления предпоследнего числа на
последнее становится равным 0:

[r_{n – 1} bmod r_n = 0]

В таком случае утверждается, что:

[gcd(a, b) = r_n]

Для доказательства этого утверждения сначала докажем следующее:
наборы общих делителей пары ((a, b)) и пары ((b, r_1)) полностью совпадают.
Рассмотрим произвольный (не обязательно наибольший) общий делитель (a) и (b):

(t) – общий делитель (a) и (b).

(r_1 = a bmod b), или (a = bq + r_1).

Докажем, что (t) также является общим делителем (b) и (r_1).

(b) делится на (t) по определению.

(r_1 = a – bq = t * ({a over t} – {b over t} * q)), где ({a over t}) и ({b over t}) целые по определению.

Значит, (r_1) также делится на (t), что и требовалось доказать.

Из того, что все общие делители пар ((a, b)) и ((b, r_1)) совпадают,
в частности следует, что (gcd(a, b) = gcd(b, r_1)).

Далее по индукции можно доказать следующее:

[gcd(a, b) = gcd(b, r_1) = gcd(r_1, r_2) = ldots = gcd(r_{n – 1}, r_n) = gcd(r_n, 0)]

(Нуль в последнем выражении появился из условия (r_{n – 1} bmod r_n = 0)).

Нуль делится на все числа, отличные от нуля, поэтому справедливо следующее
свойство:

[gcd(x, 0) = x, для любого x in mathbb{N}.]

Следовательно,

[gcd(a, b) = r_n,]

что и требовалось доказать.

Варианты реализации алгоритма Евклида на C++

Существует несколько вариантов реализации алгоритма Евклида, как итеративных
так и рекурсивных. Классическая итеративная реализация (работающая быстрее всех
рекурсивных) выглядит так:

1
2
3
4
5
6
7
8
9
10
11
12
int gcd(int a, int b) {
    if (a < b) {
        swap(a, b);
    }

    while (b) {
        a %= b;
        swap(a, b);
    }

    return a;
}

Рекурсивно это же можно реализовать так:

1
2
3
4
5
6
7
8
9
10
11
int gcd(int a, int b) {
    if (a < b) {
        swap(a, b);
    }

    if (b) {
        return gcd(b, a % b);
    } else {
        return a;
    }
}

Преимущество рекурсивной реализации заключается в возможности записать её в
очень кратком виде (предполагающим, что (a > b)):

1
2
3
int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

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

Время работы алгоритма Евклида

Согласно некоторым исследованиям, время работы алгоритма Евклида тесно
связано с числами Фибоначчи. Это выражается, в частности, в том, что два
последовательных числа Фибоначчи – наихудшие входные данные для алгоритма
Евклида. При (a = F_n, b = F_{n – 1}), алгоритм Евклида совершит ровно
(n – 2) итерации. Отсюда можно выразить асимптотическую сложность алгоритма:
последовательность Фибоначчи возрастает с экспоненциальной скоростью, поэтому
алгоритм Евклида работает за (O(log min(a, b))).

Наименьшее общее кратное

С понятием НОД связано также понятия наименьшего общего кратного (англ.
least common multiple). Наименьшее общее кратное двух натуральных чисел –
наименьшее натуральное число, которое делится на каждое из них. Оно обозначается
следующим образом:

[lcm(a, b)]

и связано с НОД формулой:

[lcm(a, b) = {a * b over gcd(a, b)}]

Реализация на C++:

1
2
3
4
5
int lcm(int a, int b) {
    return a / gcd(a, b) * b;   //используя форму a * b / gcd(a, b),
                                //можно получить переполнение на этапе a * b,
                                //поэтому следует выполнять деление до умножения
}

Взаимнопростые числа

Числа (a) и (b) называются взаимнопростыми тогда и только тогда, когда они
не имеют общих делителей отличных от (1). То есть в их отношении должно
выполняться условие (gcd(a, b) = 1).

НОД и НОК для произвольного количества чисел

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

[gcd(a, b, c, d) = gcd(gcd(gcd(a, b), c), d)]

[lcm(a, b, c, d) = lcm(lcm(lcm(a, b), c), d)]

Алгоритм Евклида – это алгоритм для поиска наибольшего общего делителя двух чисел. Алгоритм впервые описан древнегреческим математиком Евклидом.

Наибольший общий делитель (НОД) – это наибольшее число, на которое делятся заданные числа без остатка.

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

Рекурсивная реализация поиска наибольшего общего делителя

Напишем два вспомогательных метода, которые возвращают минимальное и максимальное из двух чисел:

static int Min(int x, int y)
{
    return x < y ? x : y;
}

static int Max(int x, int y)
{
    return x > y ? x : y;
}

Нахождение НОД для двух чисел c использованием вычитания

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

static int GCD(int a, int b)
{
    if (a == 0)
    {
        return b;
    }
    else
    {
        var min = Min(a, b);
        var max = Max(a, b);
        //вызываем метод с новыми аргументами
        return GCD(max - min, min);
    }
}

Использование оператора остатка от деления % для вычисления НОД

Для уменьшения количества рекурсивных вызовов, при вычислении, можно воспользоваться оператором остатка от деления и вместо разницы, передавать в метод остаток от деления максимального числа на минимальное.
Чтобы ускорить алгоритм, достаточно изменить знак в строке возврата предыдущего метода с “-” на “%”:

return GCD(max % min, min);

Использование остатка очень ускоряет работу алгоритма поиска НОД. К примеру для пары чисел 1013 и 65 с использованием вычитания метод вызывается 27 раз, а с остатком от деления всего 7.

Вычисление НОД в циклах

Циклическое вычисление наибольшего общего делителя с вычитанием

static int GCD(int a, int b)
{
    if (a == 0)
    {
        return b;
    }
    else
    {
        while (b != 0)
        {
            if (a > b)
            {
                a -= b;
            }
            else
            {
                b -= a;
            }
        }

        return a;
    }
}

Циклический поиск наибольшего общего делителя с остатком от деления

static int GCD(int a, int b)
{
    while (b != 0)
    {
        var temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

Программа для поиска НОД чисел

Напишем программу, в которой будем использовать один из методов рассмотренных выше:

using System;

class Program
{
    static int GCD(int a, int b)
    {
        while (b != 0)
        {
            var t = b;
            b = a % b;
            a = t;
        }
        return a;
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Алгоритм Евклида");
        Console.Write("A = ");
        var a = Convert.ToInt32(Console.ReadLine());
        Console.Write("B = ");
        var b = Convert.ToInt32(Console.ReadLine());
        Console.WriteLine("Наибольший общий делитель чисел {0} и {1} равен {2}", a, b, GCD(a, b));
        Console.ReadLine();
    }
}

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

Для чисел 36 и 60 программа возвращает значение 12.

Наибольший общий делитель трех чисел

Для получения НОД для трех чисел и более чисел необходимо вызывать метод следующим образом:

var n1 = GCD(GCD(15, 30), 75); //для трех параметров результат 15
var n2 = GCD(GCD(16, 36), GCD(585, 360)); //для четырех чисел результат 1

В первом примере сначала вычисляется НОД(15, 30) = 15, потом результат вычислений передается в качестве аргумента и вычисляется НОД(15, 75) = 15.
Во втором примере вычисляются НОД(16, 36) = 4 и НОД(585, 360) = 45, а результаты передаются в метод НОД(4, 45) = 1.

Смотрите также:

Добавить комментарий