개발저장소
[백준 실버 2] 1699번: 제곱수의 합 본문
문제
https://www.acmicpc.net/problem/1699
1699번: 제곱수의 합
어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다
www.acmicpc.net
풀이
- 자연수 N을 제곱수의 합으로 표현해야 한다. 예를 들어 5 = 1^2 + 2^2, 즉 2개의 항으로 나타낼 수 있다.
- 이때 N을 제곱수의 합으로 나타낼 때, 최소 항의 개수를 구한다.
- 모든 자연수 N의 최대 항의 개수는 N개이다. 1^2의 합으로 표현할 수 있기 때문이다.
- 제곱수 N의 최소 항의 개수는 무조건 1개이다. 제곱해서 N이 되는 수 하나만 존재하는 경우가 이에 해당한다.
- N의 범위는 1 이상 100,000 이하이다.
N의 값이 최대 100,000이기 때문에 위 성질을 이용해 점화식을 만들어 풀어야 한다.
정수형 배열 dp를 선언한다. 이때 dp[i]는 자연수 i를 제곱수의 합으로 나타낼 때 최소 항의 개수이다.
비교하기 전 dp[i]의 초기값은 i로 선언할 수 있다. 모든 자연수 N의 최대 항의 개수는 N개이기 때문이다.
int dp[] = new int[N + 1];
for (int i = 1; i <= N; i++) {
dp[i] = i;
// ...
}
항의 개수를 줄이기 위해서는 제곱수가 필요하다. 즉, dp[i]를 구하기 위해서는 i보다 작은 제곱수를 알 필요가 있다.
예를 들어 N = 12이라면, 12보다 작은 제곱수는 1, 4, 9가 있다.
dp[12]는 dp[12 - 1], dp[12 - 4], dp[12 - 9] 중에서 제일 작은 값에 1을 더한 것이다. dp[i]는 이미 최소 항의 개수이므로 자연스럽게 dp[12]는 위 세 경우 중 최소값에서 1을 더하면 된다.
for (int j = 1; j * j <= i; j++) {
if (dp[i] > dp[i - j * j] + 1) {
dp[i] = dp[i - j * j] + 1;
}
}
전체 코드 (Java)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int dp[] = new int[N + 1];
for (int i = 1; i <= N; i++) {
dp[i] = i;
for (int j = 1; j * j <= i; j++) {
if (dp[i] > dp[i - j * j] + 1) {
dp[i] = dp[i - j * j] + 1;
}
}
}
System.out.println(dp[N]);
}
}
후기
다이나믹 프로그래밍 문제는 풀 때마다 새롭다. 다른 문제들과 성격이 약간 다른 만큼 꾸준히 풀어서 까먹지 않도록 해야겠다.
'Coding Test > Baekjoon' 카테고리의 다른 글
[백준 실버 2] 12891번: DNA 비밀번호 (0) | 2023.12.08 |
---|---|
[백준 골드 4] 1253번: 좋다 (0) | 2023.12.07 |
[백준 골드 3] 10986번: 나머지 합 (0) | 2023.11.28 |
[백준 실버 5] 2628번: 종이자르기 (0) | 2023.11.21 |
[백준 골드 4] 1806번: 부분합 (0) | 2023.11.08 |