https://www.acmicpc.net/problem/4883
4883번: 삼각 그래프
입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 그래프의 행의 개수 N이 주어진다. (2 ≤ N ≤ 100,000) 다음 N개 줄에는 그래프의 i번째 행에 있는 정점의 비용이
www.acmicpc.net
코드설명
동적계획법(DP, Dynamic Programming) 을 활용하는 문제입니다.
문제에서 map[][] 은 각각 현재줄에서의 첫번째, 두번째, 세번째 수를 선택했을때의 최소 비용을 나타냅니다.
문제에서 유의해야할점들입니다.
1. 그림의 화살표 방향을 이해해야합니다.
즉, 반드시 내려가는것이 아닌, 옆을 거치면서도 갈 수 있습니다.
2. 시작점은 반드시 map[0][1] 입니다.
시작점은 반드시 map[0][1]이므로 사실상 map[0][0] 을 거칠일은 없습니다. 또한 그래프 그림을 보면 실제로 map[0][1]에서 map[0][0]으로 가는 길이 없습니다.
3. 끝점은 반드시 map[N-1][1] 입니다. (끝점도 가운데로 고정되어있습니다.)
저는 가장 첫번쨰 행과 두번째 행은 시작점이 고정되어있어 먼저 처리한 후에 아래부터는 반복문을 사용해 일반화시켜 게산했습니다.
코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int N, M, K; public static int answer = 0; public static int[][] map; public static int[][] dp; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int T = 0; while(true) { StringTokenizer st = new StringTokenizer(br.readLine()); K = Integer.parseInt(st.nextToken()); if(K == 0) return ; map = new int[K][3]; dp = new int[K][3]; for(int i=0;i<K;i++) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int c = Integer.parseInt(st.nextToken()); map[i][0] = a; map[i][1] = b; map[i][2] = c; } simulate(); T+=1; System.out.println(T+". "+map[K-1][1]); } } public static void simulate() { map[0][2] += map[0][1]; map[1][0] += map[0][1]; map[1][1] += Math.min(map[1][0], Math.min(map[0][1], map[0][2])); map[1][2] += Math.min(map[0][1], Math.min(map[1][1], map[0][2])); for(int i=2; i<K;i++) { map[i][0] = Math.min(map[i-1][0], map[i-1][1]) + map[i][0]; map[i][1] = Math.min(Math.min(map[i][0], map[i-1][0]), Math.min(map[i-1][1], map[i-1][2])) + map[i][1]; map[i][2] = Math.min(Math.min(map[i][1], map[i-1][1]), map[i-1][2]) + map[i][2]; } } }
정답코드2입니다.
재귀와 메모이제이션을 활용합니다.
아래의 코드를 작성하면서 놓쳤었던 부분은,
// ret = Math.min(ret, DFS(depth - 1, next) ) + matrix[depth][now]; ret = Math.min(ret, DFS(depth - 1, next) + matrix[depth][now]);
이 코드입니다.
저는 처음에 주석처리한 코드방식으로 작성했습니다만, 오류가 났습니다.
왜 그럴까요?
바로, 여러번 matrix[depth][now]가 더해질 수 있다는 점입니다.
예시를 들어보겠습니다.
만약 첫번쨰 재귀에서 DFS(depth -1, next)로 갱신되고, matrix[depth][now]까지 더해졌습니다.
두번째 재귀에서 이전 ret이 min값이고 이번의 재귀값은 min값이 아니었습니다. 하지만 여전히 matrix[depth][now]가 더해집니다.
이렇게 되면 계속 ret값에 추가값이 더해지겠지요.
그러므로 DFS(depth -1, next) + matrix[depth][now] 와 같이 두번쟤 방식으로 코드를 작성해야만 중복 더하기 연산이 발생하지 않습니다.
package Main; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; import java.util.StringTokenizer; public class Main { static int N, M, S, P, A, B, X, L, R, C, n, k, m, l, K, D, T; static int[] answer = new int[2]; static int[][] matrix; static long[][] cache = new long[100001][3]; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int num = 0; while(true) { StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); if(N == 0) return ; matrix = new int[N][3]; for(int i=0; i<100001; i++) { Arrays.fill(cache[i], -1); } for(int i=N-1;i>=0; i--) { st = new StringTokenizer(br.readLine()); for(int j=0; j<3; j++) { matrix[i][j] = Integer.parseInt(st.nextToken()); } } System.out.println(++num+". "+ DFS(N-1, 1)); } } static long DFS(int depth, int now) { if(depth == 0 && now == 1) return matrix[depth][now]; if(depth == -1) return 100000 * 1000 + 1; if(cache[depth][now] != -1) return cache[depth][now]; long ret = 100000 * 1000 + 1; if(now == 0) { ret = Math.min(ret, DFS(depth, 1) + matrix[depth][now]); } if(now == 1) { ret = Math.min(ret, DFS(depth, 2) + matrix[depth][now]); } for(int dir : new int[] {-1, 0, 1}) { int next = now + dir; if(next < 0 || next >= 3) continue; // ret = Math.min(ret, DFS(depth - 1, next) ) + matrix[depth][now]; ret = Math.min(ret, DFS(depth - 1, next) + matrix[depth][now]); } return cache[depth][now] = ret; } }
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 11559 Puyo Puyo - Simulation(시뮬레이션) + BFS(너비우선탐색) JAVA (0) | 2023.12.20 |
---|---|
[백준] 15655 N과 M (6) - 백트래킹(BackTracking) JAVA (0) | 2023.12.19 |
[백준] 11967 불켜기 - BFS(너비우선탐색) JAVA (0) | 2023.12.17 |
[백준] 16920 확장 게임 - BFS(너비우선탐색) JAVA (0) | 2023.12.17 |
[백준] 2750 숨바꼭질 4 - BFS(너비우선탐색) + 부모경로찾기(find Parent, LCA) JAVA (0) | 2023.12.16 |