0. 문제 |
1. 아이디어 |
1) 야호!!!
2) 해당 문제에서 내가 사용할 dp[i]의 컨셉은 i의 구성하는 최소항들의 개수이다! 그렇다면 그 이후의 수들은 이전 dp값들을 잘 이용한다면 쉽게 최소 제곱수들의 합으로 나타낼 수 있다. ex) dp[80] = dp[64] + dp[16], dp[96] = dp[80] + dp[16]
3) (핵심) 예를 들어 32의 경우와 같이 해당 숫자 이하의 가장 큰 제곱수가 반드시 포함되어야만 하는 건 아니다. ex) 32 = 16 + 16 (O), 25 + 4 + 2 + 1 (X) 그래서 가장 가까이에 있는 제곱수부터 1까지의 케이스를 확인하며 최솟값을 찾으면 된다!
2. 소스코드 |
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
|
#include <iostream>
#include <algorithm>
#include <math.h>
int dp[100001];
int main()
{
int N, cur = 1; // cur은 현재 값에서 가장 가까운 제곱수
std::cin >> N;
for (int i = 1; i <= (int)sqrt(N); i++)
dp[i * i] = 1; //제곱수들은 항의 최소 개수를 1로 초기화
for (int i = 1; i <= N; i++)
{
if (dp[i])
{
cur = i;
continue;
}
int result = dp[i - cur] + dp[cur];
for (int j = sqrt(cur) - 1; j > 0; j--)
result = std::min(result, dp[i - j * j] + dp[j * j]);
dp[i] = result;
}
std::cout << dp[N];
}
|
cs |
3. 결과 |
4. 피드백 |
-
쉬워보였는데 정말 예상치도 못하게 애먹었다..
-
역시 아직 실력이 많이 부족하다.
-
항상 많은 예외가 존재하니 할 수 있는 최대한의 경우의 수를 고려해야한다!
'알고리즘 > BOJ' 카테고리의 다른 글
[C++] 백준 2225번 - 합분해 (1) | 2020.03.25 |
---|---|
[C++] 백준 9461번 - 파도반 수열 (0) | 2020.03.25 |
[C++] 백준 2579번 - 계단 오르기 (0) | 2020.03.23 |
[C++] 백준 1912번 - 연속합 (0) | 2020.03.23 |
[C++] 백준 11054번 - 가장 긴 바이토닉 부분 수열 (0) | 2020.03.22 |