- 백준의 정수론 문제를 살펴보다, 유클리드 호제법에 대해 알게 되었다.
- 어떤 것인지 간단하게 파악하고, 이를 이용해 문제를 푼 것에 대해 짤막히 기록한다.
유클리드 호제법
- 자연수 혹은 정수 사이의 최대공약수(Greatest Common Denominator: GCD)를 구하기 위한 알고리즘.
- a와 b의 최대공약수는, a / b의 나머지 r과 b의 최대공약수와 같다.
이를 실제 함수로 구현하면 재귀 혹은 반복을 통해 구현할 수 있다. 나는 아래와 같은 코드를 작성해 문제풀이에 활용하였다.
const getGCD = (a, b) => {
if (a === b) return a;
if (a === 1 || b === 1) return 1;
if (b === 0) return a;
return getGCD(b, a % b);
};
문제 풀이
개념을 간단하게 파악하고 간단한 문제 풀이를 해보았다.
백준 1934번
말그대로 최소공배수를 구하는 문제. 위에서 공부한 유클리드 호제법은 두 수 사이의 최대공약수를 구하는 알고리즘이지만, a와 b사이의 최소공배수는 두 수를 곱한 것을 최대공약수로 나누면 도출*되므로 이에 활용할 수 있다.
* 참고
따라서 유클리드 호제법을 사용하여 최대공약수를 구하고, 위에서 언급한대로 최소공배수를 계산하면 된다.
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let input = [];
let answer = "";
const getGCD = (a, b) => {
if (a === b) return a;
if (a === 1 || b === 1) return 1;
if (b === 0) return a;
return getGCD(b, a % b);
};
rl.on("line", (line) => {
input.push(line.split(" ").map((el) => parseInt(el)));
}).on("close", function () {
for (let i = 1; i < input.length; i++) {
let a = input[i][0];
let b = input[i][1];
if (a === 1 || b === 1) {
answer += `${a === 1 ? b : a}\n`;
} else {
const gcd = getGCD(a, b);
if (gcd === 1) answer += `${a * b}\n`;
else {
const leastMultiple = (a * b) / gcd;
answer += `${leastMultiple}\n`;
}
}
}
console.log(answer.trim());
process.exit();
});
백준 1735번
두 분수를 더하고, 그 결과를 기약분수로 나타내는 문제. 입력받은 두 분수를 더한 다음, 분자와 분모의 최대공약수를 구해 분모/분자를 나누면 기약분수를 쉽게 구할 수 있다.
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let input = [];
const getGCD = (a, b) => {
if (a === b) return a;
if (a === 1 || b === 1) return 1;
if (b === 0) return a;
return getGCD(b, a % b);
};
rl.on("line", (line) => {
input.push(line.split(" ").map((el) => parseInt(el)));
}).on("close", function () {
let denominator = input[0][1] * input[1][1];
let numerator = input[0][0] * input[1][1] + input[1][0] * input[0][1];
const gcd = getGCD(denominator, numerator);
console.log(numerator / gcd, denominator / gcd);
process.exit();
});
백준 2485번
임의의 간격으로 심어진 가로수 사이 최소한의 나무만을 심어 나무 사이 간격이 똑같아지도록 만드는 문제. 나무 사이의 간격을 구하고, 간격들 간의 최대공약수를 구하면 된다는 것을 파악했으나 두 개 이상의 수에 대해 최대공약수를 어떻게 구하면 될지 몰라 망설이던 중, N개의 수에 대해 최대공약수를 구하는 방법에 대해 알게 되었다. 첫 두 수의 최대공약수를 구한 후, 그 최대공약수와 다음 수의 최대공약수를 구하는 것을 반복하면 N개의 수의 최대공약수를 구할 수 있다고.
이를 유클리드 호제법을 사용해 구현하여 문제를 푼 코드가 아래와 같다.
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let input = [];
const getGCD = (a, b) => {
if (a === b) return a;
if (a === 1 || b === 1) return 1;
if (b === 0) return a;
return getGCD(b, a % b);
};
rl.on("line", (line) => {
input.push(parseInt(line));
}).on("close", function () {
const distance = [];
// 나무 사이의 간격을 구함
for (let i = 1; i < input.length - 1; i++) {
distance.push(input[i + 1] - input[i]);
}
let gcd = distance[0];
// 간격들의 최대공약수를 구함
for (let j = 1; j < distance.length; j++) {
gcd = getGCD(gcd, distance[j]);
}
console.log((input[input.length - 1] - input[1]) / gcd + 1 - input[0]);
process.exit();
});
- 평소 백준의 단계별로 풀어보기를 애용하는 편인데, 다양한 유형의 문제를 접하고 모르던 개념을 알 수 있어 무척 유용한 것 같다.
'공부 > 알고리즘' 카테고리의 다른 글
그래프 & DFS/BFS 문제 풀이 (2) | 2023.11.19 |
---|---|
그래프 + 그래프 순회 정리 (0) | 2023.11.17 |
백준에서 JS로 문제 풀이하기 + 이런저런 메모(+추가: 2023.11.22) (3) | 2023.10.23 |
백트래킹 (1) | 2023.10.15 |
[~0718] 알고리즘 (0) | 2021.07.19 |