PS/백준

[BOJ] 백준 2096번 : 내려가기 (JAVA)

제이온 (Jayon) 2020. 8. 28.

문제

N줄에 0 이상 9 이하의 숫자가 세 개씩 적혀 있다. 내려가기 게임을 하고 있는데, 이 게임은 첫 줄에서 시작해서 마지막 줄에서 끝나게 되는 놀이이다.

 

먼저 처음에 적혀 있는 세 개의 숫자 중에서 하나를 골라서 시작하게 된다. 그리고 다음 줄로 내려가는데, 다음 줄로 내려갈 때에는 다음과 같은 제약 조건이 있다. 바로 아래의 수로 넘어가거나, 아니면 바로 아래의 수와 붙어 있는 수로만 이동할 수 있다는 것이다. 이 제약 조건을 그림으로 나타내어 보면 다음과 같다.

 

 

 

 

별표는 현재 위치이고, 그 아랫 줄의 파란 동그라미는 원룡이가 다음 줄로 내려갈 수 있는 위치이며, 빨간 가위표는 원룡이가 내려갈 수 없는 위치가 된다. 숫자표가 주어져 있을 때, 얻을 수 있는 최대 점수, 최소 점수를 구하는 프로그램을 작성하시오. 점수는 원룡이가 위치한 곳의 수의 합이다.

 

 

입력

첫째 줄에 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 숫자가 세 개씩 주어진다. 숫자는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 중의 하나가 된다.

 

 

출력

첫째 줄에 얻을 수 있는 최대 점수와 최소 점수를 띄어서 출력한다.

 

 

풀이

다이나믹 프로그래밍과 슬라이딩 윈도우 기법을 사용하여 풀 수 있는 문제였습니다.

슬라이딩 윈도우 기법에 대해 모르시는 분은 아래 포스팅을 참조하시길 바랍니다.

 

 

 

[Algorithm] 슬라이딩 윈도우(Sliding Window) 알고리즘

슬라이딩 윈도우 알고리즘 슬라이딩 윈도우 알고리즘은 윈도우 즉 일정한 범위를 가지고 있는 것을 유지하면서 이것을 이동(sliding) 하는 것이다. 예를들어 2가지 긴 문자열이 주어지고 알파벳 2�

ramees.tistory.com

 

 

이 문제에서 위 기법을 사용한 이유는 단순합니다.

제한 메모리가 4MB 밖에 안 되기 때문이죠.

 

메모리 제한이 없었다면, 입력값을 모두 입력받아서 int[][] 타입의 dp를 정의하고 다이나믹 프로그래밍을 수행할 수 있을 것입니다. 하지만, 4MB 밖에 안 되는 메모리에 최대 100,000 * 100,000 짜리 배열을 저장할 수 없습니다.

 

따라서, 슬라이딩 윈도우 기법을 차용하여 int[] 타입의 dp를 정의한 후, 이 dp를 연속적으로 초기화를 해 주면 됩니다.

문제의 예시를 보면서 어떻게 적용하는지 알아봅시다.

 

 

예시

3

1 2 3

4 5 6

4 9 0

 

위와 같이 N = 3 이고, 위치에 대한 정보가 나와있습니다.

 

먼저, 최댓값부터 구해봅시다. dp 배열은 int[] maxDp 로 정의합니다.

우선, 입력값을 처음 받는 경우, 즉 첫째 줄의 값은 그대로 maxDp에 넣어줍니다.

maxDp[0] = 1, maxDp[1] = 2, maxDp[2] = 3 이 될 것입니다.

 

다음으로, 둘째 줄을 살펴봅시다.

maxDp[0] 은 입력값 4 또는 5 로 이동할 수 있고,

maxDp[1] 는 입력값 4 또는 5 또는 6 으로 이동할 수 있고,

maxDp[2] 는 입력값 5 또는 6으로 이동할 수 있습니다.

 

이를 다르게 표현하면 다음과 같습니다.

maxDp[0] -> max(maxDp[0], maxDp[1]) + input[0]

maxDp[1] -> max(maxDp[0], maxDp[1], maxDp[2]) + input[1]

maxDp[2] -> max(maxDp[1], maxDp[2]) + input[2]

 

위에서 maxDp[0] 은 입력값 4 또는 5로 이동할 수 있다고 하였는데,

입력값 4 가 곧, 다음 maxDp[0] 이며, 입력값 5 가 다음 maxDp[1] 가 되기 때문입니다.

 

다만, 위 식을 그대로 코드로 옮기게 되면, maxDp[0] 은 큰 값으로 초기화된 상태로 maxDp[1] 과 maxDp[2] 를 올바른 값으로 초기화하지 못한다는 점을 주의하시길 바랍니다.

하지만, 설명의 편의성을 위해서 위 식을 차용해서 풀이하겠습니다.

 

이제, 점화식을 이해했다면 둘째 줄부터 다시 전개해 봅시다.

maxDp[0] = max(maxDp[0], maxDp[1]) + input[0] = max(1, 2) + 4 = 2 + 4 = 6

maxDp[1] = max(maxDp[0], maxDp[1], maxDp[2]) + input[1] = max(1, 2, 3) + 5 = 3 + 5 = 8

maxDp[2] = max(maxDp[1], maxDp[2]) + input[2] = max(2, 3) + 6 = 3 + 6 = 9

 

따라서 기존에 있던 maxDp 배열의 값이 maxDp[0] = 6, maxDp[1] = 8, maxDp[2] = 9 가 되었음을 알 수 있습니다.

 

세 번째 줄도 전개해 봅시다.

maxDp[0] = max(maxDp[0], maxDp[1]) + input[0] = max(6, 8) + 4 = 8 + 4 = 12

maxDp[1] = max(maxDp[0], maxDp[1], maxDp[2]) + input[1] = max(6, 8, 9) + 9 = 9 + 9 = 18

maxDp[2] = max(maxDp[1], maxDp[2]) + input[2] = max(8, 9) + 0 = 9

 

따라서 기존에 있던 maxDp 배열의 값이 maxDp[0] = 12, maxDp[1] = 18, maxDp[3] = 9 가 되었음을 알 수 있습니다.

 

N개의 줄을 모두 탐색했으면, maxDp 배열 중 가장 큰 값을 최댓값으로 출력하면됩니다.

마찬가지로, 최솟값은 minDp를 정의하여 위 과정을 min으로만 바꿔서 수행하면 끝입니다.

 

 

아래는 위 과정을 정리한 소스코드입니다.

 

 

소스코드

 

지적 혹은 조언 환영합니다! 언제든지 댓글로 남겨주세요.

댓글

추천 글