티스토리 뷰

728x90
반응형

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

 

1699번: 제곱수의 합

어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다

www.acmicpc.net

보면 간단한 dp문제이다. 하지만, 보다 더 효율적으로 알 수 있는 방법이 존재한다. 

S3에서 해결하였던 four squares 문제와 비슷하다.

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

 

17626번: Four Squares

라그랑주는 1770년에 모든 자연수는 넷 혹은 그 이하의 제곱수의 합으로 표현할 수 있다고 증명하였다. 어떤 자연수는 복수의 방법으로 표현된다. 예를 들면, 26은 52과 12의 합이다; 또한 42 + 32 + 1

www.acmicpc.net

우선 dp로 해결해보자. 

그냥 하나하나 찾는 것이다. 입력된 값 n으로 시작하여 1 ~ i^2이 n이 되기 전까지 하나하나 살펴보고, 가장 작은 값을 넣어주는 것이다.

i가 1일때 dp[n - 1] + 1

i가 2일때 dp[n - 4] + 1

...

이렇게 말이다. 이 중에서 가장 작은 값을 넣어주면 된다 코드도 간단하게 다음과 같이 나온다.

#include <cstdio>
#include <cmath>

int main(void) {
    int N, dp[100001]{ 0, 1 }; scanf("%d", &N);

    for (int i = 2; i <= N; i++) {
        dp[i] = 1e9;
        for (int j = std::sqrt(i); j > 0; j--) {
            if(dp[i] > dp[i - j * j] + 1) dp[i] = dp[i - j * j] + 1;
        }
    }
    printf("%d", dp[N]);
}

 

하지만, 이 문제는 하나 엄청난 비밀이 숨겨져 있다. 바로 모든 숫자는 제곱으로 이루어진 숫자로 최대 4개밖에 없다. 제곱수 5개 이상으로 이루어진 숫자가 없다는 것이다. 이유는 나도 잘..

이것을 이용해서 하나하나 살펴보는 방법이 존재한다.

코드는 다음과 같다.

#include <cstdio>

int main(void) {
    int n; scanf("%d", &n);

    int i, j, k, l;
    for (i = 0; i < 318; i++) {
        for (j = i; j < 318; j++) {
            for (k = j; k < 318; k++) {
                int sum = i * i + j * j + k * k;
                if (sum > n) break;
                else if (sum == n) {
                    if (j == 0) printf("1");
                    else if (i == 0) printf("2");
                    else printf("3");
                    return 0;
                }
            }
        }
    }
    printf("4");
}
728x90
반응형

'코딩테스트 > Silver 2' 카테고리의 다른 글

[S2] 1182. 부분수열의 합  (0) 2022.10.27
[S2] 18870. 좌표 압축  (0) 2022.10.27
[S2] 10971. 외판원 순회 2  (0) 2022.10.26
[S2] 5397. 키로거  (0) 2022.10.25
[S2] 18111. 마인크래프트  (0) 2022.10.25