문제 확인
dp 문제입니다.
left, right를 나누어 dp를 작성하면 dp[500000][500000]이 되므로 메모리 초과가 일어나기 때문에 | left-right | 를 기준으로 dp를 작성해야 합니다.
풀이
탐색 횟수를 줄이기 위해 입력 받은 수를 정렬하고 현재 단계에서 갈 수 있는 최댓값까지 탐색을 합니다.
조각을 쌓을 때 2가지 경우로 나눌 수 있습니다.
- 높은 탑에 쌓기 : 높은 탑에 쌓는 경우 현재 dp[j] 를 가리키고 있으며 dp[j + ary[i]] 값에 최댓값이 저장됩니다.
- 낮은 탑에 쌓기 : 이 경우 낮은 탑에 ary[i]를 쌓았을 때 옆의 탑보다 높아지는 경우가 있으므로 2가지 경우가 더 생깁니다.
- j < ary[i] : 이 경우 낮은 탑이 더 높아지게 되므로 dp[ary[i] - j]를 가리키게 됩니다.
- j > ary[i] : 반대로 dp[j - ary[i]] 가 됩니다.
따라서 점화식을 세워보면 다음과 같습니다.
dp[j + ary[i] = max(dp[j + ary[i], dp[0][j] + ary[i])
if (j < ary[i])
dp[1][ary[i] - j] = max(dp[1][ary[i] - j], dp[0][j] + ary[i] - j);
else
dp[1][j - ary[i]] = max(dp[1][j - ary[i]], dp[0][j]);
주의해야 할 점은 dp 배열을 0~max_len 까지 작성한 후 다음 i 루프에서 사용해야 하므로 dp[2][500000]을 사용합니다.
코드
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
|
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mx(a,b)a>b?a:b
using namespace std;
int main() {
int n;
int ary[50], dp[2][500001];
memset(dp, -1, sizeof dp);
dp[0][0] = dp[1][0] = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &ary[i]);
sort(ary, ary + n);
for (int i = 0, max_len = 0; i < n; i++) {
for (int j = 0; j <= max_len; j++) {
if (dp[0][j] == -1)continue;
dp[1][j + ary[i]] = max(dp[1][j + ary[i]], dp[0][j] + ary[i]);//높은 블록에 쌓기
if (j < ary[i]) //낮은 블록에 쌓기
dp[1][ary[i] - j] = max(dp[1][ary[i] - j], dp[0][j] + ary[i] - j);
else
dp[1][j - ary[i]] = max(dp[1][j - ary[i]], dp[0][j]);
}
max_len += ary[i];
memcpy(dp[0], dp[1], 4 * (max_len + 1));
}
printf("%d", dp[0][0] > 0 ? dp[0][0] : -1);
}
|
cs |
반응형
'알고리즘 문제 > [백준]' 카테고리의 다른 글
[백준] 14245 XOR (0) | 2021.02.22 |
---|---|
[백준] 1915 가장 큰 정사각형 (0) | 2021.02.22 |
[백준] 20541 앨범정리 (0) | 2021.02.20 |
[백준] 16225 제271회 웰노운컵 (0) | 2021.02.16 |
[백준] 2879 코딩은 예쁘게 (0) | 2021.02.14 |