Почему алгоритм Евклида находит НОД и как его реализовать?
Наибольший общий делитель двух целых чисел сохраняется, если большее число заменить остатком от деления на меньшее. Это свойство превращает медленный перебор делителей в короткую последовательность делений. Алгоритм Евклида важен не только как приём, но и как образец доказуемого уменьшения задачи.
Ключевое равенство
Пусть a = bq + r. Любой общий делитель a и b делит разность a − bq, то есть r. Обратно, общий делитель b и r делит bq + r, значит, делит a. Следовательно, множества общих делителей пар (a, b) и (b, r) совпадают.
Итерационный процесс
Пока b не равно нулю, вычисляют r = a mod b и заменяют пару на (b, r). Остаток по модулю положительного b лежит от нуля до b − 1, поэтому второй компонент строго уменьшается. При b = 0 ответом становится модуль a.
Нули и отрицательные числа
Принято считать gcd(a, 0) = |a|. Знаки исходных чисел не влияют на положительный НОД, поэтому в начале можно перейти к модулям. Случай gcd(0, 0) зависит от принятого определения и должен быть явно оговорён в контракте задачи.
Расширенный вариант
Вместе с остатками можно восстанавливать коэффициенты x и y такие, что ax + by = gcd(a, b). Расширенный алгоритм используется для решения линейных диофантовых уравнений и нахождения обратного элемента по модулю. Его корректность следует из тех же замен пар.
Трассировка
Для пары 252 и 105 выпишите столбцы a, b, q и r до нулевого остатка. Затем проверьте последний ненулевой остаток прямым делением обоих исходных чисел. В устном ответе обязательно проговорите сохранение множества общих делителей и строгую убываемость остатка.
Остаток сохраняет общий делитель
Равенство gcd(a, b) = gcd(b, a mod b) следует из представления a = qb + r: любой общий делитель a и b делит r, а общий делитель b и r делит a. Значит, множество общих делителей не меняется. Второй аргумент уменьшается, поэтому процесс заканчивается.
def gcd(a: int, b: int) -> int:
a, b = abs(a), abs(b)
while b != 0:
a, b = b, a % b
return a
def lcm(a: int, b: int) -> int:
return 0 if a == 0 or b == 0 else abs(a // gcd(a, b) * b)
assert gcd(252, 105) == 21
assert lcm(12, 18) == 36В НОК деление выполняется до умножения, чтобы снизить риск переполнения в языках с фиксированной разрядностью. Нормализация знака делает контракт функции однозначным, включая пару отрицательных аргументов.
Практика: коэффициенты Безу
Постройте таблицу итераций для 252 и 105: a, b, частное и остаток. Затем реализуйте расширенный алгоритм Евклида, возвращающий g, x, y, для которых ax + by = g. Проверьте равенство программно для положительных и отрицательных входов. В дополнительной задаче используйте коэффициент x для поиска обратного элемента по модулю m и объясните, почему решение существует только при gcd(a, m) = 1.
Источники
- МФТИ: Программа вступительного испытания по информатике и информационно-коммуникационным технологиям.
- МФТИ: Вступительные испытания в 2026 году.
- Семакин И.Г., Хеннер Е.К., Шеина Т.Ю. Информатика. 11 класс. Базовый уровень.