대표적인 다이나믹 프로그래밍(dp) 문제.
문제에 쓰여있는 대로 재귀함수 w(a,b,c)
를 탑다운으로 구현하면 된다.
다만, 정말 그대로 하면 시간초과가 나기 때문에 메모이제이션으로 풀어야 한다.
그대로 구현하고 20, 20, 20 입력하면 함수가 10341번정도 호출된다.
메모이제이션으로 하지 않으면 20, 20, 20이 여러 번 입력되면 그만큼 계속 호출된다.
a
, b
, c
중 적어도 하나가 0보다 같거나 작거나 20보다 크면 상수값을 반환하기 때문에
1부터 20까지만 기억할 수 있게 하면 된다.
index에 -1하기 귀찮아서 그냥 21*21*21 의 배열을 만들었다.
내가 푼 풀이는 dp[a][b][c] == 0 일 때 값을 넣어주는 방식이다.
w(a,b,c) 가 0이 되는 (a,b,c) 쌍이 많다면 시간이 오래 걸릴 거라 생각했다.
a,b,c에 1~20을 각각 넣고 최종적인 dp의 값들을 확인해 봤다.
다행히? w(a,b,c) 가 0이 되는 (a,b,c) 쌍은 존재하지 않았다.
[Python3]
12345678910111213141516171819 def w(a,b,c):if a <= 0 or b <= 0 or c <= 0:return 1if a > 20 or b > 20 or c > 20:return w(20,20,20)if dp[a][b][c] == 0:if a < b and b < c:dp[a][b][c] = w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c)else:dp[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)return dp[a][b][c]import sys; r=sys.stdin.readlinedp = [[[0]*21 for _ in range(21)] for _ in range(21)]while True:a,b,c = map(int, r().split())if a == -1 and b == -1 and c == -1:breakprint('w(%d, %d, %d) = %d' %(a,b,c,w(a,b,c)))
[Java]
12345678910111213141516171819202122232425262728 import java.io.*;import java.util.Arrays;public class Main{static int[][][] dp;public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));dp = new int[21][21][21];while(true){int[] num = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();if(num[0] == -1 && num[1] == -1 && num[2] == -1) break;System.out.printf("w(%d, %d, %d) = %d\n",num[0],num[1],num[2],w(num[0],num[1],num[2]));}}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 w(20, 20, 20);if(dp[a][b][c] == 0){if(a < b && b < c){dp[a][b][c] = w(a,b,c-1) + w(a,b-1,c-1) - w(a,b-1,c);}else{dp[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);}}return dp[a][b][c];}}