[BOJ] 백준 2096번 : 내려가기 (JAVA)
문제
N줄에 0 이상 9 이하의 숫자가 세 개씩 적혀 있다. 내려가기 게임을 하고 있는데, 이 게임은 첫 줄에서 시작해서 마지막 줄에서 끝나게 되는 놀이이다.
먼저 처음에 적혀 있는 세 개의 숫자 중에서 하나를 골라서 시작하게 된다. 그리고 다음 줄로 내려가는데, 다음 줄로 내려갈 때에는 다음과 같은 제약 조건이 있다. 바로 아래의 수로 넘어가거나, 아니면 바로 아래의 수와 붙어 있는 수로만 이동할 수 있다는 것이다. 이 제약 조건을 그림으로 나타내어 보면 다음과 같다.
별표는 현재 위치이고, 그 아랫 줄의 파란 동그라미는 원룡이가 다음 줄로 내려갈 수 있는 위치이며, 빨간 가위표는 원룡이가 내려갈 수 없는 위치가 된다. 숫자표가 주어져 있을 때, 얻을 수 있는 최대 점수, 최소 점수를 구하는 프로그램을 작성하시오. 점수는 원룡이가 위치한 곳의 수의 합이다.
입력
첫째 줄에 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 숫자가 세 개씩 주어진다. 숫자는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 중의 하나가 된다.
출력
첫째 줄에 얻을 수 있는 최대 점수와 최소 점수를 띄어서 출력한다.
풀이
다이나믹 프로그래밍과 슬라이딩 윈도우 기법을 사용하여 풀 수 있는 문제였습니다.
슬라이딩 윈도우 기법에 대해 모르시는 분은 아래 포스팅을 참조하시길 바랍니다.
이 문제에서 위 기법을 사용한 이유는 단순합니다.
제한 메모리가 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으로만 바꿔서 수행하면 끝입니다.
아래는 위 과정을 정리한 소스코드입니다.
소스코드
지적 혹은 조언 환영합니다! 언제든지 댓글로 남겨주세요.
'PS > 백준' 카테고리의 다른 글
[BOJ] 백준 1309번 : 동물원 (JAVA) (0) | 2020.08.29 |
---|---|
[BOJ] 백준 2688번 : 줄어들지 않아 (JAVA) (0) | 2020.08.28 |
[BOJ] 백준 11062번 : 카드 게임 (JAVA) (0) | 2020.08.27 |
[BOJ] 백준 11869번 : 님블 (JAVA) (0) | 2020.08.27 |
[BOJ] 백준 1915번 : 가장 큰 정사각형 (JAVA) (2) | 2020.08.27 |
댓글