Apple is Apple

1. 문제

상근이는 학생들에게 두 양의 정수 A와 B의 최대공약수를 계산하는 문제를 내주었다. 그런데, 상근이는 학생들을 골탕먹이기 위해 매우 큰 A와 B를 주었다.

상근이는 N개의 수와 M개의 수를 주었고, N개의 수를 모두 곱하면 A, M개의 수를 모두 곱하면 B가 된다.

이 수가 주어졌을 때, 최대공약수를 구하는 프로그램을 작성하시오.

2. 입력 및 출력

  • 입력: 첫째 줄에 N(1 ≤ N ≤ 1000)이 주어진다. 둘째 줄에는 N개의 양의 정수가 공백으로 구분되어 주어진다. 이 수는 모두 1,000,000,000보다 작고, N개의 수를 곱하면 A가 된다.

셋째 줄에 M(1 ≤ M ≤ 1000)이 주어진다. 넷째 줄에는 M개의 양의 정수가 공백으로 구분되어 주어진다. 이 수는 모두 1,000,000,000보다 작고, M개의 수를 곱하면 B가 된다.

  • 출력: 두 수의 최대공약수를 출력한다. 만약, 9자리보다 길다면, 마지막 9자리만 출력한다. (최대 공약수가 1000012028인 경우에는 000012028을 출력해야 한다)

3. 풀이

여러 개의 수를 두 줄에 걸쳐 입력 받고 그 각 줄 마다 입력 받은 수를 모두 곱한다. 곱한 후 나온 두 수의 최대공약수를 구하면 되는 문제이다.

단, 문제에서 주어진 조건인 각 줄의 수의 개수(1~1000), 최대 999,999,999이므로 수를 모두 곱하게 되면 최악의 경우(999,999,999^1000)이기 떄문에 Int(-2^31 ~ 2^31-1), Long(-2^63 ~ 2^63-1) 타입으로는 담을 수 없는 수가 나오므로 BigInteger 클래스를 사용한다.

최대공약수를 구할 때는, 유클리드 호제법(유클리드 알고리즘)을 사용하여 수를 구한다.

4. 코드

<code />
import java.io.BufferedWriter import java.io.OutputStreamWriter import java.util.* import java.math.BigInteger import kotlin.math.sqrt val bw = BufferedWriter(OutputStreamWriter(System.out)) fun main() = with(System.`in`.bufferedReader()) { val n = readLine().toInt() val list1 = readLine().split(" ").map{it.toBigInteger()} val m = readLine().toInt() val list2 = readLine().split(" ").map{it.toBigInteger()} // 각 수를 구하기 위한 변수 선언 var mul1 = BigInteger("1") var mul2 = BigInteger("1") // 입력 받은 수들을 모두 곱함 for(i in list1) { mul1 *= i } for(i in list2) { mul2 *= i } // 최대공약수 알고리즘 실행 val gcd = gcd(mul1, mul2).toString() // 문제 조건에 따라 9자리가 넘어가면 뒤 9자리만 출력 when{ gcd.length > 9 -> { bw.write(gcd.takeLast(9)) } else -> { bw.write(gcd) } } bw.flush() bw.close() close() } fun gcd(n: BigInteger, m: BigInteger): BigInteger { return if (n < m) { if (n == BigInteger("0")) m else gcd(n, m % n) } else { if (m == BigInteger("0")) n else gcd(m, n % m) } }

4.1. 유클리드 알고리즘

유클리드 알고리즘(유클리드 호제법)은 두 수의 최대공약수를 구하는 알고리즘이다.

알고리즘 진행:

  1. 두 수 n, m이 있고 n < m 인 관계이다.
  2. m을 n으로 나눈 나머지를 k 라고 할 때, k가 0이게 되면 n이 최대 공약수이다. k가 0이 아니면 n보다 더 큰 수가 m을 나누어 떨어지게 할 수 있으므로 최대공약수가 될 수 없다.
  3. 2번을 토대로 k가 0이 아니라면, m을 n값으로 치환하고, n을 k값으로 치환 한 후, 2번 과정을 반복하여 나머지가 0이 될때까지 수행한다.

이렇게 m, n 값을 바꾸어주면서 초기 m 값을 나누어 떨어지게 할 수 있는 값을 찾을 수 있게된다.

4.2. BigInteger

Int(-2^31 ~ 2^31-1), Long(-2^63 ~ 2^63-1) 타입으로는 담을 수 없을 경우가 발생 할 수도 있다.
이때 BigInteger 클래스를 사용할 수 있다.
BigInteger 클래스는 내부적으로 문자열 형태로 수가 이루어져 있어 숫자의 범위를 무한하게 지정하여 사용할 수 있다. (물론, 디바이스의 메모리의 영향은 받을 것이다.)

이 문제는 위의 2가지 개념을 조합하여 해결을 하였다.

5. 결과

image

BigInteger를 사용하다보니 메모리를 꽤 쓴 모습을 볼 수 있다.

profile

Apple is Apple

@mjjjjjj