Skip to content
On this page

백준 1699 JavaScript

수정하기
문서 생성 2022-01-27 10:42:31 최근 수정 2022-04-29 20:53:15
On this page

문제

백준 1699

풀이

Dynamic Programming을 이용해 풀이를 하면,
DP라는 배열에 해당 인덱스 값을 표현할 수 있는 제곱수 항의 최소 개수를 넣는다고 가정하자. 예를 들어, 숫자 "24"의 경우는 DP[24]에 24를 제곱수들의 합으로 표현할 때 그 항의 최소 개수가 들어가게 된다.

이 최소 개수를 구하려면 어떻게할까?
24를 예로 들면 24보다 작은 제곱수들은 1, 4, 6, 9, 16이 있다.
이 제곱수들을 이용해 합을 구성할 수 있는 방법은 다음 4가지 중 하나일 것이다.

(24 - 1²)의 최소 개수 + 1(1²)
(24 - 2²)의 최소 개수 + 1(2²)
(24 - 3²)의 최소 개수 + 1(3²)
(24 - 4²)의 최소 개수 + 1(4²)

따라서 위 식은 아래와 같이 나올 수 있다. 이 값들 중 최소인 경우를 구하면 된다.

DP[24] = DP[23] + 1
DP[24] = DP[20] + 1
DP[24] = DP[15] + 1
DP[24] = DP[8] + 1

제곱수들의 합으로 표현할 때 가장 큰 경우는 모두 1의 제곱으로 이루어진 경우일 것이다. 따라서 최대개수는 그 수 자신이다. 우선 그 값으로 DP 배열을 초기화를 해준다.

24 = 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1² + 1²

그 다음, 2부터 순회를 시작한다.

const readFileSyncPath = require('path').basename(__filename).replace(/js$/, 'txt');
// const readFileSyncPath = '/dev/stdin';
const N = Number(require('fs').readFileSync(readFileSyncPath).toString().trim());
// 1의 제곱으로만 이루어진 제곱수 항의 개수 = 값 자신
const DP = Array.from({ length: N + 1}, (v, i) => i);
// 2부터 N까지 순회
for (let i = 2; i <= N; i++) {
// 어떤 수의 제곱이 해당 값보다 작은 경우 까지
for (let j = 2; j * j <= i; j++) {
// 해당 값에 제곱을 뺀 경우 최소 개수에 + 1을 한 것과 -> (해당 값 - 어떤 수(j)의 제곱)의 항의 개수에 어떤 수(j)의 제곱을 더한 것
// 현재 해당 값 중 더 작은 것으로 변경
DP[i] = Math.min(DP[i], DP[i - j * j] + 1);
}
}
console.log(DP[N]);