1. 최대공약수를 구하는 방법
1) 약수를 이용하여 구하기
2) 두 수의 차이를 이용하여 구하기
3) 유클리드 호제법을 이용하여 구하기
4) 소인수분해를 이용하여 구하기
2. 방법 별 구현 코드 예시
1-1) 약수를 이용한 방법
int a, b, tmp;
scanf("%d %d", &a, &b);
for (int i = 2; i <= a && i <= b; i++)
{
if (a % i == 0 && b % i == 0) tmp = i;
else tmp = 1;
}
printf("%d", tmp);
두 수 중에서 작은 수 까지 반복문을 실행한다. 그 이유는 두 수의 공약수는 항상 두 수 중 작은 수의 약수 중에서 존재하기 때문이다. (ex. 18의 약수는 1,2,3,6,9,18 이고, 6의 약수는 1,2,3,6 이다. 이떄 18의 약수 중에서 9와 18은 6(18과 6 중 작은 수)의 약수에 없으므로 공약수가 될 수 없다.)
두 수의 공약수로 그 수를 나누면 나누어 떨어진다. 이것으로 판별하여 tmp에 작은 값부터 차례대로 입력되므로 반복문이 끝나면 tmp는 최대공약수가 저장 될 것이다. 만약 두 수를 나누어 떨어지게하는 수가 없다면, 1을 tmp에 입력한다.
2) 두 수의 차이를 이용한 방법
위 에서 a와 b는 서로소이다.
위를 통해서 A-B (두 수의 차)는 G(최대공약수)의 배수이다. 그러므로 A-B의 약수 중에서 G(최대공약수)가 있다.
설명한대로 코드를 작성해보겠다.
두 수 a와 b중 큰 값에서 작은수를 빼야한다. 이 동작을 두 수가 같아 질 때까지 반복하면 2개의 케이스가 발생한다. 첫번째는 두 수가 1이 아닌 최대공약수로 같을 때이고, 두번째는 두 수가 1로 같을 때이다.
int a, b;
scanf("%d %d", &a, &b);
while (a != b)
{
if (a >= b) a -= b;
else b -= a;
}
printf("%d\n", a);
3) 유클리드 호제법을 이용한 방법
두 자연수 A와 B(A ≥ B)일 때,
A ÷ B=q ··· r (q≠0)에서 A=Bq+r (0≤ r 〈 B)이다.
따라서, 두 수 A와 B의 최대공약수는 Bq+r와 B의 최대공약수와 동치이다.
Bq는 B의 배수이고, r은 B의 배수가 아니다. 그러므로 A와 B의 최대 공약수는 B와 r의 최대공약수라고 할 수 있다.
정리) A와 B의 최대공약수는 A를 B로 나눈 나머지가 r 일 때, B와 r의 최대공약수와 같음. (단, A ≥ B)
아래 참고. (k는 임의의 몫.)
b[0] b[1]
b[0]/b[1]=k ··· b[2]
b[1]/b[2]=k ··· b[3]
b[2]/b[3]=k ··· b[4]
⋮
b[n]/b[n+1]=k ... b[n+2]
b[n+2]==0 -> GCD: b[n+1]
b[n+2]==1 -> GCD: 1
-------------------------
b[0] b[1]
b[2]=b[0]%b[1]
b[3]=b[1]%b[2]
⋮
b[n+2]=b[n]%b[n+1]
b[n+2]==0 -> GCD: b[n+1]
b[n+2]==1 -> GCD: 1
아래 코드는 위의 구상을 토대로 보기 편하게 작성해 보았다.
int a[5] = {};
scanf("%d %d", &a[0], &a[1]);
int i = 0;
while (1)
{
a[i + 2] = a[i] % a[i + 1];
if (a[i + 2] == 0)
{
printf("%d\n", a[i + 1]);
break;
}
if (a[i + 2] == 1)
{
printf("%d\n", a[i + 2]);
break;
}
i++;
}
4) 소인수분해를 이용한 방법
72와 90을 소인수분해하면 다음과 같다.
이때 최대공약수는 두 수의 공통인 소수를 모조리 선택하여 곱한 값이다.
즉, 72와 90의 최대공약수는 2X3^2=18이다.
int isPrime(int n)
{
if (n <= 1)
return 0;
for (int i = 2; i * i <= n; ++i)
{
if (n % i == 0)
return 0;
}
return 1;
}
int primeFactorization(int n, int factors[])
{
int index = 0;
for (int i = 2; i <= n; ++i)
{
while (n % i == 0 && isPrime(i))
{
factors[index++] = i;
n /= i;
}
}
return index;
}
int gcd(int a, int b)
{
int factors_a[100] = {0};
int factors_b[100] = {0};
int cnt_a = primeFactorization(a, factors_a);
int cnt_b = primeFactorization(b, factors_b);
int gcd = 1;
int i = 0, j = 0;
while (i < cnt_a && j < cnt_b)
{
if (factors_a[i] == factors_b[j])
{
gcd *= factors_a[i];
i++;
j++;
}
else if (factors_a[i] < factors_b[j])
i++;
else
j++;
}
return gcd;
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
int result = gcd(a, b);
printf("%d\n", result);
return 0;
}
3. 구현한 코드별 실행 시간 비교
2121212121와 1212121212의 최대공약수를 각 코드마다 5번 실행시 걸리는 시간의 평균
1) 약수를 이용하여 구하기 ⇒ 평균 3800ms
2) 두 수의 차이를 이용하여 구하기 ⇒ 평균 2.6ms
3) 유클리드 호제법을 이용하여 구하기 ⇒ 평균 3ms
4) 소인수분해를 이용하여 구하기 ⇒ 평균 67.4ms
'C,C++' 카테고리의 다른 글
C언어; 달팽이 배열 이해하기 (0) | 2024.12.17 |
---|---|
C언어; 10진수를 2진수로 변환하는 알고리즘 (3) | 2024.06.06 |
C; 배열 정렬 알고리즘 (버블 정렬, 삽입정렬, 퀵 정렬, 힙 정렬, 병합 정렬) (1) | 2024.06.06 |
댓글