View

300x250

문제링크

https://www.acmicpc.net/problem/1699

문제

어떤 자연수 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)

출력

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

조건

  • 시간 제한 : 2s
  • 메모리 제한 : 128MB

해설

제곱수의 합으로 나타내고자 하였으므로, 해당 수를 만들 수 있는 가장 큰 제곱수를 최대한 이용하여야 한다. DP 벡터를 만들어 이전에 선택했던 최소의 방법에서 1가지 방법을 늘리는 방법으로 최소의 방법을 이어나간다.

풀이

자연수 i에 대해 1부터 i보다 작은 제곱수까지 각 k라고 할 때, dp[i-k] 의 값에 1을 더한 값 중 가장 작은 값이 dp[i]가 된다. 예를 들어, i가 43일 때, dp[43]은 43에서 제곱수를 종류별로 하나씩 뺐을 때 dp의 값이 가장 작은 방법을 선택하는 것이 가장 최소의 방법을 사용할 수 있다. dp[42], dp[39], dp[34], dp[27], dp[18], dp[7] 중 가장 작은 값 + 1이 된다.

for(int i = 1; i <= N; i++) {
    int temp = 1;
    int min = 100000;
    while (temp*temp <= i) {
        if(dp[i-temp*temp] + 1 < min) {
            min = dp[i-temp*temp] + 1;
        }
        temp++;
    }
    
    dp[i] = min;
}


코멘트

할 만 했군 그래.


코드

#include <iostream>
#include <vector>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    
    int N;
    cin >> N;
    vector<int> dp(N+1);
    
    dp[0] = 0;
    
    for(int i = 1; i <= N; i++) {
        int temp = 1;
        int min = 100000;
        while (temp*temp <= i) {
            if(dp[i-temp*temp] + 1 < min) {
                min = dp[i-temp*temp] + 1;
            }
            temp++;
        }
        
        dp[i] = min;
    }
    
    cout << dp[N];
    return 0;
}
320x100

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

[백준] 11051 - 이항 계수 2  (0) 2021.12.25
[백준] 10872 - 팩토리얼  (0) 2021.12.25
[백준] 11055 - 가장 큰 증가 부분 수열  (0) 2021.12.25
[백준] 2225 - 합분해  (0) 2021.12.25
[백준] 1904 - 01타일  (0) 2021.12.25
Share Link
reply
반응형
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31