본문 바로가기
(구) 자료/Baekjoon Online Judge

[DP] 백준 #1699 / 제곱수의 합

by 뜐뜐뜐 2018. 1. 10.
시간 제한메모리 제한제출정답맞은 사람정답 비율
2 초128 MB75563115233440.605%

문제

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다. 이 경우, 수학자 숌크라테스는 “11은 3개 항의 제곱수 합으로 표현할 수 있다.”라고 말한다. 또한 11은 그보다 적은 항의 제곱수 합으로 표현할 수 없으므로, 11을 그 합으로써 표현할 수 있는 제곱수 항의 최소 개수는 3이다.

주어진 자연수 N을 이렇게 제곱수들의 합으로 표현할 때에 그 항의 최소개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 100,000)

출력

주어진 자연수를 제곱수의 합으로 나타낼 때에 그 제곱수 항의 최소 개수를 출력한다.



동전 알고리즘과 똑같은 메카니즘으로 풀어야한다.

[How To Solve?]

N을 기준으로, N보다 작은 모든 제곱수들을 N에서 뺀 값들 살펴보아야 한다. 뭔소리냐고??

예를 들어, 12라는 숫자를 만들기 위한 최소한의 제곱수들의 갯수를 구하려면, 12보다 작은 제곱수들인 1, 4, 9를 12에서 뺀 값의 dp배열을 확인해봐야 한다.

왜냐고? dp[12]를 구하기 위해서 dp[12-1], dp[12-4], dp[12-9]의 대소비교를 통해, 가장 작은 값을 찾으면 해당 dp값에서 갯수를 하나 늘리면 최소로 필요로하는 제곱수의 갯수가 나오기 때문이다.


의문점 1) 왜 저렇게 하면 최소가 나오는가?

- DP문제들은 대부분 dp[n]을 구하기 위해서 dp[n-1]에서 +1이 정답인 경우가 많다.

- 같은 패턴이라고 생각했을 때, 여기서는 n-1이 아니라, 모든 제곱수가 후보가 될 수 있다.

- 그 이유는, 만약 위에서처럼 12를 구하기 위해서 11을 구성하는 최소의 제곱수에다가 1이라는 제곱수를 더하면 최소가 될 것이고

- 8을 구성하는 최소의 제곱수에 4라는 제곱수를 더해주면 최소가 될 것이고

- 3을 구성하는 최소의 제곱수에 9라는 제곱수를 더해주면 최소가 되기 때문이다.

- 위의 세 가지 경우 모두 마지막 경우에서 갯수가 하나 늘어나는 방식이기 때문에 후보군이 될 수 있는 것이다.


의문점 2) 그렇다면 초기 값은 어떻게 잡아야 하는가?

- 우선, N보다 작거나 같은 제곱수가 2개 이상일 때, 반복문으로 대소비교를 할 수 있다고 생각했다.

- 그 이유는 다음과 같다.

1 = 1

2 = 1+1

3 = 1+1+1

4 = 4

- 위에서 잘 보면, 3에서 4로 넘어가는 순간 가능한 제곱수는 1과 4로 총 두 개가 된다.(문제에서 N이 자연수라고 줬기 때문에 0은 제외한다)

- 즉, 1,2,3까지는 어떠한 변수도 적용되지 않고 항상 고정된 값으로 보아도 무방하다는 것이다.


[Code]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
 
public class boj_1699 {
    public static void main(String args[]) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine().trim());
        int dp[] = new int[N+1];
        
        for(int i=0;i<=N;i++)
            dp[i] = i;
        
        for(int i=4;i<=N;i++
            for(int j=2;Math.pow(j, 2)<=i;j++
                dp[i] = Math.min(dp[i], dp[(int) (i-Math.pow(j, 2))]+1);
        System.out.println(dp[N]);
    }
}
 
cs