문제
- 문제 링크
BOJ 28467 - Spell Cards
$N$장의 카드가 단 하나만 남을 때까지 인접한 두 카드에 대해 마법을 시전한다.
최종적으로 소모하는 총 마력의 최솟값을 구해보자.
TL : $1$ sec, ML : $1024$ MB
$1 ≤ N ≤ 400$ $1 ≤ a_i ≤ 10^9$
알고리즘 분류
- 다이나믹 프로그래밍(dp)
풀이
BOJ 11049 - 행렬 곱셈 순서 와 비슷한 느낌을 받았다면 충분하다.
식 정의에만 조금 차이가 있을 뿐, 본질적으로 비슷한 형태로 풀 수 있다.
어떤 구간에 대해, $p == q$ 가 아닌 이상 반드시 두 연속 부분 수열로 나누어 답을 구할 수 있다.
구체적으로 구간 $[p, q]$의 답은 $p ≤ i < q$ 인 $i$에 대해 $dp[p][i] + dp[i + 1][q]$ 의 값과,
이 둘에게 마법을 시전하는 비용인
$max(a_p, a_{p+1}, ... , a_i)$ $+$ $max(a_{i+1}, a_{i+2}, ... , a_q)$ 의 합 중 최솟값이 되겠다.
연속 수열에서의 최댓값은 $O(N^2)$의 전처리를 통해 $O(1)$만에 구할 수 있고, 상태의 개수가 $N^2$개이며 각 상태를 계산하는 데에 $O(N)$의 복잡도를 가진다.
따라서 문제를 총 $O(N^3)$에 해결할 수 있다.
전체 코드
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 | #include<bits/stdc++.h> using namespace std; using ll = long long; int n, _max[401][401]; ll dp[401][401]; ll f(int p, int q) { if (p == q) return 0; ll& t(dp[p][q]), i(p); if (!~t) for (t = 1e18; i < q; i++) dp[p][q] = min(dp[p][q], f(p, i) + f(i + 1, q) + _max[p][i] + _max[i + 1][q]); return t; } int main() { memset(dp, -1, sizeof dp); cin >> n; for (int i = 1; i <= n; i++) cin >> _max[i][i]; for (int i(1); i <= n; i++) for (int j(i + 1); j <= n; j++) _max[i][j] = max(_max[i][j - 1], _max[j][j]); cout << f(1, n); } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Gold)' 카테고리의 다른 글
백준 29618 - 미술 시간 (C++) (0) | 2023.09.04 |
---|---|
백준 28472 - Minimax Tree (C++) (1) | 2023.08.27 |
백준 28707 - 배열 정렬 (C++) (0) | 2023.08.15 |
백준 23792 - K번째 음식 찾기 2 (C++) (0) | 2023.08.09 |
백준 28421 - 곱하기와 쿼리 (C++) (0) | 2023.08.05 |