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

C++로 풀어보는 나이트의 최소 이동 거리 문제

문제 소개

좌표가 -∞에서 +∞까지 뻗어 있는 무한 체스판을 상상해 봅시다. 나이트는 [0, 0] 위치에서 출발하며, 아래 그림과 같이 총 8가지 방향으로 이동할 수 있습니다. 각 이동은 한 축 방향으로 두 칸, 그에 수직인 방향으로 한 칸 움직이는 형태입니다.

C++로 풀어보는 나이트의 최소 이동 거리 문제

우리의 목표는 나이트를 목표 좌표 [x, y]로 옮기는 데 필요한 최소 이동 횟수를 구하는 것입니다. 문제 조건상 답은 항상 존재한다고 보장됩니다.

예시

입력이 x = 5, y = 5라면 출력은 4가 됩니다. 실제 이동 경로는 다음과 같습니다.

[0,0] → [2,1] → [4,2] → [3,4] → [5,5]

해결 접근 방법

이 문제는 재귀와 메모이제이션(메모화)을 결합하면 깔끔하게 해결할 수 있습니다. 핵심 아이디어는 체스판의 대칭성 때문에 음수 좌표를 모두 절댓값으로 바꿔 제1사분면 문제로 환원할 수 있다는 점입니다. 단계별 풀이 과정은 다음과 같습니다.

  • (x, y) 좌표 쌍을 키로, 해당 지점까지의 최소 이동 횟수를 값으로 저장할 맵(map)을 정의합니다.

  • solve() 함수를 정의하고, x와 y를 인자로 전달받습니다.

  • 기저 조건을 설정합니다. x + y = 0이면 이미 도착 지점이므로 0을 반환하고, x + y = 2이면 2를 반환합니다. 후자는 (1,1), (2,0), (0,2)처럼 일반적인 재귀 규칙만으로는 올바르게 계산되지 않는 특수 경우이기 때문입니다.

  • (x, y)로 임시 pair 객체 temp를 만듭니다.

  • 맵에 temp가 이미 존재하면 저장된 값을 즉시 반환하여 중복 계산을 방지합니다.

  • 그렇지 않다면, solve(|x−1|, |y−2|)와 solve(|x−2|, |y−1|) 중 더 작은 값에 1을 더한 결과를 맵에 저장한 뒤 반환합니다.

  • 메인 함수에서는 solve(|x|, |y|)를 호출해 최종 결과를 얻습니다.

C++ 구현 예제

아래 코드를 통해 구현 방식을 더 자세히 살펴보겠습니다.

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    map < pair <int, int>, int > dp;
    int solve(int x, int y){
        if(x + y == 0) return 0;
        if (x + y == 2) return 2;
        pair <int, int> temp({x, y});
        if(dp.count(temp)) return dp[temp];
        return dp[temp] = min(solve(abs(x - 1), abs(y - 2)), solve(abs(x - 2), abs(y - 1))) + 1;
    }
    int minKnightMoves(int x, int y) {
        return solve(abs(x), abs(y));
    }
};
main(){
    Solution ob;
    cout << (ob.minKnightMoves(5, 5));
}

입력

5
5

출력

4

즉, 나이트가 [5, 5] 지점에 도달하기 위해 필요한 최소 이동 횟수는 4번입니다. 메모이제이션 덕분에 동일한 좌표에 대한 탐색이 반복되지 않으므로, 무한히 넓은 체스판에서도 효율적으로 답을 구할 수 있습니다.