장르: 애초에 역경을 딛고 이룩하는 숭고한 사랑이란 없다. 그 역경 자체가 사랑이다.
프로그램 특징: 그 곳에서 살아남는 사랑이 어떤 모습으로 걸어오는지 기다려 보고 싶다.
프로그래머스 알고리즘 강좌가 dp 이해에 도움이 됐다는 글을 보고 '땅따먹기'를 시도했다. 직접 짜보고 dp 코드와 비교하니까 dp의 느낌이 확 와닿는다. dp는 모든 경우의 수를 확인하는데, 각 요소가 있고, 없고에 따라 경우를 만든다.
문제와 함께 보자
문제
ㅎ. 하지만 나는 어제 dp를 정리해 놓고도 전혀 떠오르지 않아서 풀리는 대로 풀었다. (이해가 덜 됐다ㅜ)
내 풀이 방법
1. 현재 index(j)를 이전 max의 index와 비교해 같지 않은 경우에만 들어간다.
- if ( i == 0 ) 인 예외를 주는 데 시간이 오래 걸렸다. 다시 생각해 보니 첫 열은 index가 뭐든 관계없으니까 preindex 처음 선언할 때 preindex = -1; 했으면 됐겠다.
2. index가 같지 않은 경우에만 max의 값을 업데이트할 기회를 준다.
3. max 값은 answer에 바로 저장하고 검사용 preindex를 업데이트한다.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<vector<int>> land = {
{1, 2, 3, 5},
{5, 6, 7, 8},
{4, 3, 2, 1}
};
int answer = 0, preindex, index, max;
for (int i = 0; i < land.size(); i++) {
max = 0, index = 0, preindex = 0;
for (int j = 0; j < 4; j++) {
if (i==0 or j != preindex) {
if (max < land[i][j]) {
max = land[i][j];
index = j;
}
}
}
answer += max;
preindex = index;
}
return answer;
}
테스트 코드만 통과했다. 게다가 비효율적이다. 만약에 land [ 3 ][ j ] 값을 이용한다 치면 이미 했던 계산을 또 해야 하기 때문이다.
해설은 dp를 이용했다. 이제 약간 감이 잡혔다. dp의 memoization은 갔던 모든 경로를 이전에 구한 값을 이용해 만드는 배열이다.
해설 코드
#include<vector>
using namespace std;
int dp[100001][4] = {0};
int solution(vector <vector<int> > land) {
int r = land.size();
for (int i = 0; i < 4; ++i) {
dp[0][i] = land[0][i];
}
for (int i = 0; i < r; ++i) {
for (int j = 0; j < 4; ++j) {
for(int k = 0; k < 4; ++k) {
if (j != k) {
dp[i][j] = max(dp[i][j], land[i][j] + dp[i-1][k]);
//dp에 넣을 값은 현재 land를 넣지 않는 경우와 넣는 경우(0, 1)를 말한다.
}
}
}
}
int ans = 0;
for (int i = 0; i < 4; ++i) {
ans = max(ans, dp[r-1][i]);
}
return ans;
}
위에서부터 아래로 내려가는 방법 ↓ 이랑 아래에서 위로 올라가는 코드 ↑ 가 있고, 아래에서 위로 올라가는 코드도 익숙해져야한다고 했다. 각각 하향식(Memoization)와 상향식 풀이(Tabulation) 를 의미한다. 상향식 풀이의 예는 피보나치에서 f[0] = 0, f[1] = 1 이렇게 요소의 값을 넣어놓고 이를 조합해 f[n]을 구하는 방식을 의미한다.
<어려워>
오늘 계절 미적분학 교수님께서 대학 공부는 원칙대로 차근차근 이해하는 게 아니라 일단 한 번 훑고 나중에 다시 보고 이해하는 거라고 하셨다. 아몰랑 나는 그렇게 해야겠다 (눈귀막귀)
< DP 배낭의 응용이므로 배낭을 이해하기 좋은 영상을 첨부했다. >
https://youtu.be/rhda6lR5kyQ?si=LmfgjoV-pNC0u3Sf
'Algorithm > Dynamic Programming' 카테고리의 다른 글
[JAVA][BOJ 2098] 외판원 순회와 비트 연산 (1) | 2025.05.21 |
---|---|
[JAVA][BOJ 1256] 조합: 사전 찾기 (2) | 2025.05.15 |
[백준 12865][dp] 배낭: knapsack (2) | 2024.06.30 |
[백준 1106] DP 동적프로그래밍 (0) | 2024.06.25 |