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

C++로 구현하는 체스판 나이트 확률 문제 완벽 가이드

NxN 크기의 체스판이 하나 주어지고, 나이트(기사)가 r행 c열에서 출발하여 정확히 K번 이동하려고 합니다. 행과 열은 0부터 시작하는 인덱스를 사용하므로, 좌측 상단 칸은 (0, 0), 우측 하단 칸은 (N-1, N-1)입니다.

나이트는 한 칸에서 총 8가지 방향으로 이동할 수 있으며, 그 이동 경로는 아래 다이어그램과 같습니다.

C++로 구현하는 체스판 나이트 확률 문제 완벽 가이드

나이트는 이동할 때마다 8가지 가능한 이동 중 하나를 무작위로 선택합니다. 나이트는 정확히 K번 이동을 마치거나 체스판 밖으로 벗어날 때까지 계속 움직입니다. 우리가 구해야 하는 것은 나이트가 이동을 멈췄을 때 여전히 체스판 위에 남아 있을 확률입니다.

예를 들어 입력이 N=3, K=2, r=0, c=0이라면 출력은 0.0625가 됩니다. 그 이유는 첫 번째 이동에서 체스판에 남아 있는 경우의 수가 두 가지((1,2), (2,1))뿐이고, 각 위치에서도 체스판에 머무는 이동이 두 가지씩 존재하기 때문입니다. 따라서 나이트가 체스판에 남아 있을 총 확률은 0.0625가 됩니다.

문제 해결 접근 방법

이 문제는 재귀 호출과 메모이제이션(Memoization)을 활용한 동적 계획법(DP)으로 효율적으로 해결할 수 있습니다. 단계별로 살펴보겠습니다.

  • 8가지 이동 방향을 담은 배열 dir을 정의합니다: [[-2,-1], [-2,1], [2,-1], [2,1], [1,2], [1,-2], [-1,2], [-1,-2]]
  • x, y, n, k, 그리고 3차원 배열 dp를 인자로 받는 재귀 함수 solve()를 정의합니다.
  • 만약 x >= n 또는 y >= n 또는 x < 0 또는 y < 0이라면(체스판 밖), 0을 반환합니다.
  • k가 0이면(모든 이동 완료), 1을 반환합니다.
  • dp[k][x][y]가 -1이 아니라면(이미 계산된 값), 해당 값을 반환합니다.
  • dp[k][x][y]를 0으로 초기화합니다.
  • i를 0부터 7까지 반복하면서 dp[k][x][y] += solve(x+dir[i][0], y+dir[i][1], n, k-1, dp)를 누적합니다.
  • dp[k][x][y]를 반환합니다.

메인 함수에서는 다음 작업을 수행합니다.

  • (K+1) x N x N 크기의 3차원 배열을 생성하고 모든 값을 -1로 초기화합니다.
  • solve(r, c, N, K, dp) / 8^K를 반환합니다. 전체 경우의 수는 각 이동마다 8가지이므로 8^K가 됩니다.

아래 구현 예제를 통해 더 자세히 이해해 보겠습니다.

예제 코드

#include <bits/stdc++.h>
using namespace std;
int dir[8][2] = {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {1, 2}, {1, -2}, {-1, 2}, {-1, -2}};
class Solution {
    public:
    double solve(int x, int y, int n, int k, vector < vector < vector < double > > >& dp){
       if(x >= n || y >= n || x < 0 || y < 0 ) return 0.0;
       if(k == 0) return 1.0;
       if(dp[k][x][y] != -1) return dp[k][x][y];
       dp[k][x][y] = 0;
       for(int i = 0; i < 8; i++){
           dp[k][x][y] += solve(x + dir[i][0], y + dir[i][1], n, k - 1, dp);
       }
       return dp[k][x][y];
    }
    double knightProbability(int N, int K, int r, int c) {
       vector < vector < vector < double > > > dp (K + 1, vector < vector < double > >(N, vector < double >(N, -1))) ;
       return solve(r, c, N, K, dp) / pow(8, K);
    }
};
main(){
    Solution ob;
    cout << (ob.knightProbability(3, 2, 0, 0));
}

입력

3
2
0
0

출력

0.0625