https://www.acmicpc.net/problem/9184
코드설명
동적계획법과 메모이제이션을 활용합니다.
문제푸는 것은 어렵지 않았지만, 메모리초과가 발생하였습니다.
메모리 초과가 발생한 이유는, 매번의 테스트케이스마다 새로 cache = new int[51][51][51]과 같이 설정했기 때문입니다.
이렇게 설정한 이유는, 각 상태값들이 함수마다 모두 다르기에 값이 다르게 사용될 것이라 생각했는데, 생각해보면 같은 상태라면 다른 테스트케이스여도 모두 동일합니다.
그러므로 전역으로 cache 배열을 선언하도록 하고, 처음에는 [51][51][51]로 cache배열을 선언했었는데, 의사코드를 보면 20 20 20 이상일경우 무조건 w(20, 20, 20)을 선언하는 것을 볼 수 있었습니다.
그러므로, [21][21][21] 로 바꿔주고, ArrayIndexOutOfException 이 발생하지 않게 적절하게 함수의 위치를 수정해주면 됩니다.
특히, a > 20 || b> 20 || c> 20 부분에서 cache[a][b][c] 대신에 cache[20][20][20]으로 바꾸어서 처리하면 ArrayOutOfException이 손쉽게 해결됩니다. cache[20][20][20]인 이유는 a, b, c가 20 20 20 으로 호출될떄의 반환값을 의미하기에 그렇습니다.
처음에 푼 코드와 개선한 코드를 작성했습니다.
코드
개선한 코드입니다. 메모리를 낭비하지 않습니다.
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static int N, C, H, W, K, M, T, a, b, c;
static int answer = 0;
static int[] arr;
static int[][][] cache;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
cache = new int[21][21][21];
for(int i=0;i<21; i++) {
for(int j=0; j<21; j++) {
Arrays.fill(cache[i][j], -1);
}
}
while(true) {
StringTokenizer st = new StringTokenizer(br.readLine());
a = Integer.parseInt(st.nextToken());
b = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
if(a == -1 && b == - 1 && c == -1) {
return ;
}
System.out.println("w("+a+", "+b+", "+c+") = "+w(a, b, c));
}
}
static int w(int a, int b, int c) {
if(a <= 0 || b <= 0 || c <= 0) {
return 1;
}
if( a > 20 || b > 20 || c > 20) {
return cache[20][20][20] = w(20, 20, 20);
}
if(cache[a][b][c] != -1) return cache[a][b][c];
if(a < b && b < c) {
return cache[a][b][c] = w(a, b, c-1) + w(a, b-1, c- 1) - w(a, b-1, c);
}
return cache[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
}
}
처음에 푼 코드입니다. 2000ms, 즉 2초가 걸립니다. 상당히 느린것을 알 수 있습니다.
cache 배열은 밖으로 빼서 처리하여 메모리초과를 벗어날 수 있습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static int N, C, H, W, K, M, T, a, b, c;
static int answer = 0;
static int[] arr;
static int[][][] cache;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
cache = new int[51][51][51];
while(true) {
StringTokenizer st = new StringTokenizer(br.readLine());
a = Integer.parseInt(st.nextToken());
b = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
if(a == -1 && b == - 1 && c == -1) {
return ;
}
for(int i=0;i<51; i++) {
for(int j=0; j<51; j++) {
Arrays.fill(cache[i][j], -1);
}
}
System.out.println("w("+a+", "+b+", "+c+") = "+w(a, b, c));
}
}
static int w(int a, int b, int c) {
if(a <= 0 || b <= 0 || c <= 0) {
return 1;
}
if(cache[a][b][c] != -1) return cache[a][b][c];
if( a > 20 || b > 20 || c > 20) {
return cache[a][b][c] = w(20, 20, 20);
}
if(a < b && b < c) {
return cache[a][b][c] = w(a, b, c-1) + w(a, b-1, c- 1) - w(a, b-1, c);
}
return cache[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 11279 최대 힙 - 우선순위큐(PriorityQueue) JAVA (0) | 2024.09.02 |
---|---|
[백준] 11213 양 한마리... 양 두마리... - BFS(너비우선탐색) + DFS(깊이우선탐색) JAVA (0) | 2024.09.02 |
[백준] 5567 결혼식 - BFS(너비우선탐색) + DFS(깊이우선탐색) JAVA (0) | 2024.08.30 |
[백준] 4963 섬의 개수 - DFS(깊이우선탐색) JAVA (0) | 2024.08.29 |
[백준] 3758 KCPC - Sort(정렬) JAVA (0) | 2024.08.29 |