DY N DY

실력키우기 최대공약수와 최소공배수(C++) 본문

PARK/ALGORITHM

실력키우기 최대공약수와 최소공배수(C++)

손세지 2016. 5. 14. 21:13

1658 : 최대공약수와최소공배수

제한시간: 1Sec    메모리제한: 64mb
해결횟수: 1372회    시도횟수: 2525회   



두개의 자연수를 입력받아 최대 공약수와 최소 공배수를 출력하는 프로그램을 작성하시오.

 

입력 파일의 첫째 줄에는 두 개의 자연수가 주어진다. 이 둘은 10,000이하의 자연수이며 사이에 한 칸의 공백이 주어진다.



첫째 줄에는 입력으로 주어진 두 수의 최대공약수를 둘째 줄에는 입력으로 주어진 두 수의 최소 공배수를 출력한다.


 [Copy]
24 18
 [Copy]
6
72
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
/**************************************************************
    Problem: 1658
    User: a132034
    Language: C++
    Result: Success
    Time:0 ms
    Memory:1740 kb
****************************************************************/
 
 
#include    <iostream>
using namespace std;
int gcd_get(int x, int y);
int main()
{
    int a, b;
    cin >> a >> b;
    if (a < b)
        swap(b, a);
    int GCD = gcd_get(a, b);
    int LCM = (a*b) / GCD;
 
    cout << GCD << endl << LCM;
 
    return 0;
}
 
int gcd_get(int x, int y)
{
    if (x % y == 0) return y;   
    return gcd_get(y, x % y);
}


도움말 보고 푸니.. 푼다기보다 따라서 친 수준.

도움말 설명이 정말 잘 되어 있다.

도움말에도 써 있지만, 잘 익혀(외워?) 두면 쓸 일이 가끔 있을 것 같다.


최대공약수(GCD)란?
어떤 두 수 이상의 공통인 약수를 그 수들의 공약수라 하고 공약수들 중 가장 큰 수를 최대공약수라 한다. 공약수는 최대공약수의 약수가 된다.
 예를 들어 8의 약수는 1, 2, 4, 8이고
 12의 약수는 1, 2, 3, 4, 6, 12이므로 
 8과 12의 공약수는 1, 2, 4 세 개이고 
 8과 12의 최대공약수는 공약수 중 가장 큰 수인 4이다.

최소공배수(LCM)란?
 어떤 두 수 이상의 공통인 배수를 그 수들의 공배수라 하고 공배수들 중 가장 작은 수를 최소공배수라 한다. 공배수는 최소공배수의 배수가 된다.
 예를 들어 8의 배수는 8, 16, 24, 32, 40, 48.... 이고
 12의 배수는 12, 24, 36, 48, 60... 이므로 
 8과 12의 공배수는 24, 48... 이고 
 8과 12의 최소공배수는 공배수 중 가장 작은 수인 24이다.

코드1
 01   int gcd_get(int x, int y)
 02   {
 03       int i, ans;
 04       for (i = 1; i <= x; i++) {
 05           if (x % i == 0 && y % i == 0) {
 06               ans = i;
 07           }
 08       }
 09       return ans;
 10   }

11   int main()
 12   {
 13       .....
 14       gcd = gcd_get(a, b);
 15       lcm = a * b / gcd;
 16       .....
 17   }

코드분석
 gcd_get(int x, int y) 함수는 두 개의 수를 x와 y로 전달받아 최대공약수를 리턴해주는 함수이다.
 1부터 두 수중 한 개의 값(x)까지 모두 확인하면서 두 수의 공약수인지 확인하여 저장해 두었다가 그 값을 리턴하게 된다. 공약수 중 맨 마지막 값이 저장되므로 그 수가 최대공약수가 된다.
 최소공배수(lcm)는 별도의 함수를 작성하여 구할 수도 있겠지만 두 수의 최대공약수를 알고 있다면 다음의 규칙을 이용하여 쉽게 구할 수 있다.

두 수의 곱은 그 두수의 최대공약수와 최소공배수의 곱과 같다.
 a와 b의 최대공약수를 gcd(a, b), a와 b의 최소공배수를 lcm(a, b)라 하면
 a * b = gcd(a, b) * lcm(a, b)
 따라서 두 수의 최대공약수를 알 경우 최소공배수는 두 수의 곱을 최대공약수로 나눈 몫을 구하면 된다.  (lcm = a * b / gcd)

이 문제의 경우 x의 값이 최대 10000이므로 전혀 문제가 발생할 것이 없지만 만약 x의 값이 1억 이상의 큰 수라면 속도가 늦어질 수 있으므로 시간을 줄이기 위해 추가 작업이 필요하다.

시간을 줄이기 위한 방법을 몇 가지 살펴보도록 하자.
 1) 1부터 x와 y중 작은 수까지만 살펴보면 조금은 줄일 수 있지만 큰 도움이 되지는 않는다.
 2) 두 수중 한 개 수에 대한 약수를 모두 구한 후, 그 약수들 중 다른 한 개 수의 약수가 되는 최대값을 구한다. 제곱근 만큼만 반복해서 모든 약수를 구하는 방법은 앞에서 익힌 바 있다.
 3) 프로그램에서 최대공약수를 가장 빠르고 간단하게 구하는 방법은 아래에 소개하는 유클리드 호제법을 이용하는 것이다.

 유클리드 호제법(Euclidean algorithm) : 
 A를 B로 나눈 나머지가 r이라면 A와 B의 최대공약수는 B와 r의 최대공약수와 같다.   
 GCD(A, B) = GCD(B, r)
 이 원리를 이용하면 두 수의 최대공약수를 간단하게 구할 수 있다. 
 이 방법으로 24과 16의 최대공약수를 구하는 과정을 살펴보면 다음과 같다.
 GCD(30, 18) = GCD(18, 12) = GCD(12, 6) = 6
 * 30을 18로 나눈 나머지는 12, 18을 12로 나눈 나머지는 6, 12를 6으로 나눈 나머지는 0이므로, 30과 18의 최대공약수는 12와 6의 최대공약수인 6과 같다.

코드2는 유클리드 호제법을 이용하여 최대공약수를 구하는 함수이다.
코드3은 같은 내용을 재귀함수를 이용하여 더 간단하게 구현한 것이다.
최대공약수나 최소공배수등과 관련된 문제를 해결하기 위해 항상 편리하게 활용할 수 있으므로 잘 익혀두는 것이 좋다.

코드2
 01   int gcd_get(int x, int y)
 02   {
 03       int r;
 04       while (1) {
 05           r = x % y;         // 나머지를 구한후 
 06           if(r == 0) break;   // 나머지가 0이면 y가 최대공약수이므로 종료한다.
 07           x = y;             // x를 y로
 08           y = r;             // y를 r로 바꾸고 다시 반복한다.
 09        }
 10        return y;              // 최대공약수를 리턴한다.
 11    }

코드3
 01    int gcd_get(int x, int y)
 02    {
 03          if(x % y == 0) return y;    // 나머지가 0이면 y가 최대공약수이다.
 04          return (y, x % y);          // x와 y의 최대공약수는 y와 x % y 의 최대공약수와 같다.
 05    }


'PARK > ALGORITHM' 카테고리의 다른 글

실력키우기 숫자삼각형(JAVA)  (0) 2016.05.16
알고리즘 좋은수열(C++)  (0) 2016.05.16
실력키우기 마방진(JAVA)  (0) 2016.05.13
실력키우기 문자마름모(JAVA)  (0) 2016.05.12
실력키우기 별삼각형3(JAVA)  (0) 2016.05.11