Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 풀어보는 점프 게임 V (Jump Game V)

문제 개요

정수 배열 arr와 정수 d가 주어집니다. 한 번의 이동으로 인덱스 i에서 아래 두 가지 방식으로 점프할 수 있습니다.

  • i + x : 단, i + x < n 이고 x는 1부터 d 사이의 값
  • i - x : 단, i - x >= 0 이고 x는 1부터 d 사이의 값

여기서 n은 배열의 크기입니다. 추가로, 인덱스 i에서 인덱스 j로 점프하려면 arr[i] > arr[j]를 만족해야 하며, i와 j 사이에 있는 모든 인덱스 k에 대해서도 arr[i] > arr[k] 조건을 충족해야 합니다. 우리는 배열의 어떤 인덱스든 자유롭게 선택해 점프를 시작할 수 있고, 방문할 수 있는 최대 인덱스 개수를 구해야 합니다.

예시로 이해하기

예를 들어 d = 2이고 높이 배열이 다음과 같다고 가정해 보겠습니다.

C++로 풀어보는 점프 게임 V (Jump Game V)

이 경우 출력값은 4입니다. 인덱스 10에서 시작하여 10 → 8 → 6 → 7 순서로 점프할 수 있기 때문입니다.

반면 인덱스 6에서 시작하면 인덱스 7로만 점프할 수 있습니다. arr[5] = 13이 arr[6] = 9보다 크기 때문에 인덱스 5로는 점프할 수 없고, 인덱스 4와 6 사이에 인덱스 5가 끼어 있어 역시 인덱스 4로도 이동할 수 없습니다. 마찬가지로 인덱스 3에서 인덱스 2나 인덱스 1로 점프하는 것도 불가능합니다.

해결 전략: 메모이제이션 기반 DFS

이 문제는 각 인덱스에서 시작했을 때 방문할 수 있는 최대 칸 수를 계산한 뒤, 그중 최댓값을 찾는 방식으로 해결할 수 있습니다. 동일한 인덱스에 대한 계산이 반복되지 않도록 메모이제이션(DP 배열)을 활용합니다.

알고리즘 단계

  • 결과를 저장할 dp 배열을 정의합니다.
  • solve(arr, idx, d) 함수를 정의합니다.
  • dp[idx]가 -1이 아니라면 이미 계산된 값이므로 dp[idx]를 그대로 반환합니다.
  • ret := 1 로 초기화하고, n := 배열의 크기로 설정합니다.
  • i = idx + 1 부터 오른쪽 방향으로 탐색합니다.
    • i > idx + d 이면 반복을 종료합니다. (점프 거리 초과)
    • arr[i] >= arr[idx] 이면 반복을 종료합니다. (더 높거나 같은 지점은 통과 불가)
    • ret := max(ret, 1 + solve(arr, i, d)) 로 최댓값을 갱신합니다.
  • i = idx - 1 부터 왼쪽 방향으로 동일하게 탐색합니다.
    • i < idx - d 이면 반복을 종료합니다.
    • arr[i] >= arr[idx] 이면 반복을 종료합니다.
    • ret := max(ret, 1 + solve(arr, i, d)) 로 최댓값을 갱신합니다.
  • dp[idx] := ret 을 저장한 후 ret을 반환합니다.
  • 메인 함수에서는 모든 인덱스를 시작점으로 삼아 solve()를 호출하고, 그 결과의 최댓값을 반환합니다.

C++ 구현 코드

#include <bits/stdc++.h>
using namespace std;
class Solution {
   public:
   vector<int> dp;
   int solve(vector <int>& arr, int idx, int d){
      if (dp[idx] != -1)
      return dp[idx];
      int ret = 1;
      int n = arr.size();
      for (int i = idx + 1; i < n; i++) {
         if (i > idx + d)
         break;
         if (arr[i] >= arr[idx])
         break;
         ret = max(ret, 1 + solve(arr, i, d));
      }
      for (int i = idx - 1; i >= 0; i--) {
         if (i < idx - d)
         break;
         if (arr[i] >= arr[idx])
         break;
         ret = max(ret, 1 + solve(arr, i, d));
      }
      return dp[idx] = ret;
   }
   int maxJumps(vector<int>& arr, int d) {
      int n = arr.size();
      dp = vector<int>(n, -1);
      int ret = 1;
      for (int i = 0; i < n; i++) {
         ret = max(ret, solve(arr, i, d));
      }
      return ret;
   }
};
main(){
   Solution ob;
   vector<int> v = {6,4,14,6,8,13,9,7,10,6,12};
   cout << (ob.maxJumps(v, 2));
}

입력

{6,4,14,6,8,13,9,7,10,6,12}, 2

출력

4

마무리

이 알고리즘은 각 인덱스마다 최대 d칸씩 좌우로 탐색하므로 시간 복잡도는 O(n × d)입니다. 메모이제이션 덕분에 같은 인덱스에 대한 중복 계산이 제거되어 효율적으로 동작하며, 배열의 모든 위치를 출발점으로 고려해 전체 최적해를 보장합니다.