
DP 문제를 놓치지 않아요
이전에 DP 알고리즘을 정리한 적이 있는데, 까먹은 건지 DP인걸 캐치하지 못했다.
반성 겸, 정리 겸 DP를 다시 한번 정리하려고 한다.
가장 먼저, 이 글을 정리하게 된 계기를 정리해보자.
문제 설명
이 문제를 풀면서 나는 여기까지 도달했다.
내 아이디어
1 -> 3 -> 4
-> 2 -> 5 -> 4
의문점1) 3,2 단계에서는 2의 시간만 필요한데, 이걸 이 시점에 알 수 있을까?
1 -> 3 -> 4 -> 5
2 -> 6 -> 7
의문점2) 7의 관점에서는 1,3,4,5의 시간은 필요없는데 이걸 어떻게 알 수 있을까?
그리디일까? ❌
어떤 순간의 최적인 답이 최종 정답으로 이어지지 않는다.
👉 따라서 특정 건물을 짓는데 걸리는 시간을 계산하기 위해서는 각 과정에 걸리는 값을 어딘가에 저장 후(메모제이션) 나중에 활용해야한다.
부분 문제 결과를 저장하고 재활용한다.
👉 겹치는 하위 문제 + 최적 부분 구조 + 메모이제이션(또는 테이블링)
키워드 : 최소 시간, 최대 이득, 경로 수, 누적, 겹치는 부분 문제
a -> b : dp[b] = max(dp[a]+time[b],dp[b])
dp[관련 경로] = max(dp[a]+time[관련 경로], dp[관련 경로]) package day11_GraphDeepening;
import java.io.*;
import java.util.*;
public class BOJ1005ACMCraft {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int i = 0; i < T; i++) {
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
int[] degree = new int[n + 1];
int[] time = new int[n + 1];
int[] dp = new int[n + 1];
Queue<Integer> q = new ArrayDeque<>();
st = new StringTokenizer(br.readLine());
for (int j = 1; j < n + 1; j++) {
time[j] = Integer.parseInt(st.nextToken());
}
List<Integer>[] graph = new ArrayList[n + 1];
for(int j = 1; j < n + 1; j++) {
graph[j] = new ArrayList<>();
}
for (int j = 0; j < m; j++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
graph[a].add(b);
degree[b]++;
}
int w = Integer.parseInt(br.readLine());
for (int j = 1; j < n + 1; j++) {
if (degree[j] == 0) {
q.offer(j); //i로 함
dp[j] = time[j];
}
}
while (!q.isEmpty()) {
int node = q.poll();
for (int k : graph[node]) {
degree[k]--;
dp[k] = Math.max(dp[k], time[k] + dp[node]);
if (degree[k] == 0) {
q.offer(k); //node로 해놓음
}
}
}
sb.append(dp[w]).append("\n");
}
System.out.println(sb);
}
}