문제

제곱수의 합 백준 1699번


리뷰

배열 D[i] 는 i를 제곱수의 합으로 표현했을 때 최소항의 개수를 저장한다.

기본적으로 D[i] 는 1의 제곱으로 i 개 더하면 i를 만들수 있다. D[i] = i

ex) D[1] = 1개, D[2] = 2개 ( 1^2 + 1^2 )

i를 제곱수로 표현할 때, 자신보다 작은 수의 제곱수들로만 구성되어 있다.

아래는 D[i] 의 최소항 개수를 1부터 5까지 구해본 것이다.

D[1] = 1개 ( 1^2)

D[2] = 1개 ( 2^2)

D[3] = 2개 ( 1^2 + 2^2)

D[4] =1개 ( 2^2 )

D[5] = 2개 ( 2^2 + 1^2 )

점화식은 다음과 같다.

for(i = 1; i <= n; i++){

    D[i] = i; // i를 1의 제곱의 합으로만 나타내면 항의 개수 i개  

    for(j = 1; j*j <= i; j++){  // i보다 작은 제곱수들 

        D[i] = min(D[i], D[i- j*j] + 1);

    }
}

n = 5로 주어질 때, D[5] 를 구해보자.

기본적으로 D[5] 는 1의 제곱의 합으로만 나타내서 5개의 항으로 구성할 수 있다. D[5] = 5개

5 보다 작은 제곱수는 1과 2가 있다.

그래서 i보다 작은 제곱수들(1 , 2 )의 합으로 i를 표현할 수 있다.

그래서 D[5] 는 D[2] 값에 1을 더한 경우, D[1의 제곱] 값에 1을 더한 경우 로도 나타낼 수 있다.

D[5] = D[2] + 1

D[5] = D[1] + 1

이 중에서 가장 작은 값이 D[5] 에 들어가야 한다.

D[5] = min ( 5, D[2] + 1, D[1] + 1 )


코드

#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;

// 1699번 제곱수의 합  

int D[100001]; 

int main(void){

     int n = 0 ;      
    int i, j = 0;

    scanf("%d", &n);

    for(i = 1; i <= n; i++){

        D[i] = i; // i를 1의 제곱의 합으로만 나타내면 항의 개수 i개  

        for(j = 1; j*j <= i; j++){  // i보다 작은 제곱수들 

            D[i] = min(D[i], D[i- j*j] + 1);

        }
    }

     printf("%d", D[n]);

    return 0;
} 
728x90

'알고리즘 > 백준' 카테고리의 다른 글

가장 긴 증가하는 부분 수열 백준 11053  (0) 2020.08.17
합분해 백준 2225  (0) 2020.08.17
스티커 백준 9465  (0) 2020.08.15
계단오르기 백준 2579  (0) 2020.08.15
1,2,3 더하기5 백준 15990번 c++  (1) 2020.08.15

+ Recent posts