확장 유클리드 호제법 (Extended Euclidean Algorithm)
정의
확장 유클리드 호제법 (Extended Euclidean Algorithm) 은 두 정수 a, b 에 대해 gcd(a, b) = g 를 구하면서, 동시에 ax + by = g 를 만족하는 정수 x, y 를 찾는 알고리즘. Euclid 의 호제법을 역으로 되돌아가며 계산.
기본 호제법은 5세기경 Euclid 의 원론 에 등장, 확장 버전은 17세기 Bachet / Bézout 에 의해 정형화. Bézout 의 항등식 (Bézout’s identity) 으로도 불림.
문제 상황과 동기
일차 부정 방정식 ax + by = c 의 정수해를 구할 때:
- c 가 gcd(a, b) 의 배수가 아니면 해 없음.
- c = gcd(a, b) 일 때 한 조의 해 (x₀, y₀) 를 확장 유클리드로 구하면, 일반해는
x = x₀ + k(b/g),y = y₀ - k(a/g)(k 임의 정수).
나머지 연산의 역원 (modular inverse) 을 구할 때도 핵심:
ax ≡ 1 (mod m)의 해 ⇔ax + my = 1의 정수해.- gcd(a, m) = 1 일 때만 역원 존재.
RSA 암호, 중국인의 나머지 정리 (CRT), 선형 디오판토스 방정식 등 다양한 응용.
시각화
핵심 아이디어
유클리드 호제법을 재귀로 내려가면서, 역으로 올라올 때 (x, y) 를 갱신.
gcd(a, b) = gcd(b, a mod b)
base case: gcd(g, 0) = g 일 때, g·1 + 0·0 = g 이므로 (x, y) = (1, 0).
induction: b·x' + (a mod b)·y' = g 가 이미 풀렸다고 가정.
a mod b = a - ⌊a/b⌋·b 이므로,
b·x' + (a - ⌊a/b⌋·b)·y' = g
⇒ a·y' + b·(x' - ⌊a/b⌋·y') = g
따라서 x = y', y = x' - ⌊a/b⌋·y'.
invariant: 재귀가 내려가는 동안 언제나 ax + by = gcd(a, b) 성립.
알고리즘
exgcd(a, b):
if b == 0:
return (a, 1, 0) # g = a, ax + by = a·1 + 0·0
else:
(g, x', y') = exgcd(b, a mod b)
return (g, y', x' - ⌊a/b⌋·y')
반복문 (iterative) 버전도 가능 (공간 O(1)).
구현
// 확장 유클리드: ax + by = gcd(a, b)
#include <bits/stdc++.h>
using namespace std;
// return (g, x, y) where g = gcd(a, b), ax + by = g
tuple<long long, long long, long long> exgcd(long long a, long long b) {
if (b == 0) return {a, 1, 0};
auto [g, x1, y1] = exgcd(b, a % b);
return {g, y1, x1 - (a / b) * y1};
}
int main() {
long long a, b;
cin >> a >> b;
auto [g, x, y] = exgcd(a, b);
cout << g << " " << x << " " << y << "\n";
// verify
cout << "verify: " << a*x + b*y << " == " << g << "\n";
return 0;
}240 462 -9 47
verify: 2 == 2복잡도
| 항목 | 값 |
|---|---|
| 시간 | O(log min(a, b)) |
| 공간 (재귀) | O(log min(a, b)) |
| 공간 (반복) | O(1) |
유클리드 호제법과 동일. Fibonacci 수가 worst case 입력 (연속 나눗셈 최대).
응용
1. 선형 디오판토스 방정식
ax + by = c 의 정수해:
- g = gcd(a, b) 구하고, (x₀, y₀) = exgcd(a, b) → ax₀ + by₀ = g
- c 가 g 의 배수가 아니면 해 없음
- 그렇지 않으면 (x₀ · c/g, y₀ · c/g) 가 하나의 해
- 일반해:
x = x₀·(c/g) + k·(b/g),y = y₀·(c/g) - k·(a/g)(k ∈ ℤ)
2. 모듈러 역원
a·x ≡ 1 (mod m) 의 해 ⇔ ax + my = 1:
- gcd(a, m) ≠ 1 이면 역원 없음
- exgcd(a, m) → (g, x, y), g=1 이면 x 가 역원 (mod m 로 양수화)
모듈러 역원 문서 참고.
3. 중국인의 나머지 정리 (CRT)
두 합동식 x ≡ a₁ (mod m₁), x ≡ a₂ (mod m₂) (gcd(m₁, m₂)=1) 을 합칠 때, 확장 유클리드로 m₁ 의 mod m₂ 역원 (또는 반대) 을 구함.
함정
1. 음수 입력
a, b 가 음수일 수 있을 때:
gcd(|a|, |b|)로 절대값 취하거나,- 재귀 내부에서 음수 mod 처리.
C++ / Java 의 % 는 음수에서 음수 나머지를 돌려주므로 주의.
2. 오버플로우
a, b 가 10^18 근처면 중간 a * x 가 long long 넘을 수 있음. (__int128 또는 Python).
3. x, y 의 크기
exgcd 로 나온 (x, y) 는 절댓값이 꽤 클 수 있음 (O(b), O(a)). 최소 절댓값 해를 원하면 일반해 식에서 k 조정.
4. gcd ≠ 1 일 때
ax + by = c 에서 c 가 gcd(a, b) 배수가 아니면 해 없음. 체크 누락하면 WA.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 14565 | 역원(Inverse) 구하기 | - | kokoa-lab |
| BOJ 21568 | Ax+By=C | - | kokoa-lab |
| BOJ 3955 | 캔디 분배 | - | kokoa-lab |
| BOJ 6007 | Preparing for Landing | - | kokoa-lab |
참고
이 글의 용어 (3개)
- 모듈러 역원 (Modular Multiplicative Inverse)algorithm
- 정의 정수 a 의 모듈러 역원 (modular multiplicative inverse) 은 을 만족하는 정수 x. 기호로 또는 . 존재 조건: gcd(a, m) = 1 일 때만…
- 유클리드 호제법 (Euclidean Algorithm)algorithm
- 정의 유클리드 호제법 (Euclidean Algorithm) 은 두 정수 a, b 의 최대공약수 (GCD, Greatest Common Divisor) 를 O(log min(a,…
- 중국인의 나머지 정리 (Chinese Remainder Theorem)algorithm
- 정의 중국인의 나머지 정리 (CRT) 는 다음과 같은 연립 합동식의 해가 유일 하게 존재함을 보장: 단, m1, m2, ..., mk 는 쌍마다 서로소 (pairwise copr…
💬 댓글