알고리즘 문제

[C/C++ 백준 1699번] 제곱수의 합 (Silver 3)

새파란 공대생 2020. 5. 5. 23:15

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

 

1699번: 제곱수의 합

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

www.acmicpc.net

문제를 보고 고민도 안하고 바로 쓴 코드.


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <cstdio>
#include <cmath>
using namespace std;
int main(void){
    int N,n,cnt=0;
    scanf("%d",&N);
    while(N){
        n = (int)sqrt((double)N);
        N = N - n*n;
        cnt++;
    }
    printf("%d",cnt);
}
 

 


? 틀렸다. 반례가 존재한다. 12의 경우, 2의 제곱인 4를 3번 더하면 답이 3이다. 

그래서 생각난 아이디어가, n의 제곱수들의 합의 항의 개수를 N[n]이라 할때, N[n]=min(N[n-1]+1, N[n-4]+1, ...)로 하는 방법이다. N√N번 계산하는 거라 긴가민가 했지만, 일단 짜보았다.


 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int main(void){
    int N[100001]={1,},n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++){
        int min=100001;
        int j=1;
        while(i-j*j>=0){
            if(i==j*j)
                min=1;
            if(min>N[i-j*j]+1)
                min=N[i-j*j]+1;
            j++;
        }
        N[i]=min;
    }
    printf("%d",N[n]);
}
 

해결. 하지만 가동성면에서 아직 매우 떨어지는 거 같다. 열심히 해야겠다.