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

C++로 풀어보는 다람쥐 시뮬레이션: 견과류 수집 최소 이동 거리 구하기


문제 개요

2차원 격자 위에 나무 한 그루, 다람쥐 한 마리, 그리고 여러 개의 견과류가 놓여 있습니다. 각 위치는 격자의 셀(cell) 좌표로 표현되며, 목표는 다람쥐가 모든 견과류를 하나씩 모아 나무 아래에 옮겨놓을 때 필요한 최소 이동 거리를 구하는 것입니다.

다람쥐에게는 두 가지 제약 조건이 주어집니다.

  • 한 번에 최대 한 개의 견과류만 가질 수 있습니다.
  • 상, 하, 좌, 우 네 방향으로 인접한 셀로만 이동할 수 있으며, 거리는 이동 횟수, 즉 맨해튼 거리(Manhattan Distance)로 측정합니다.

예를 들어 높이가 5, 너비가 7이고, 나무의 위치가 [2,2], 다람쥐의 위치가 [4,4], 견과류의 위치가 [[3,0], [2,5]]라면 정답은 12가 됩니다.

C++로 풀어보는 다람쥐 시뮬레이션: 견과류 수집 최소 이동 거리 구하기

문제 해결 접근법

이 문제의 핵심 아이디어는 의외로 단순합니다. 모든 견과류에 대해 "나무 → 견과류 → 나무"의 왕복 거리를 전부 더하면 기본적인 총 이동 거리가 됩니다. 하지만 첫 번째 견과류를 가져갈 때만큼은 굳이 나무에서 출발할 필요 없이 다람쥐의 현재 위치에서 바로 출발할 수 있습니다. 따라서 어느 견과류를 먼저 가져가느냐에 따라 절약되는 거리가 달라지며, 절약 거리가 가장 큰 견과류를 첫 대상으로 삼으면 됩니다.

구체적인 풀이 단계는 다음과 같습니다.

  1. calc() 함수 정의 — x1, y1, x2, y2를 입력받아 두 지점 사이의 맨해튼 거리 |x1 − x2| + |y1 − y2|를 반환합니다.
  2. minDistance() 함수 정의 — 높이(height), 너비(width), 나무 위치 배열(tree), 다람쥐 위치 배열(sq), 견과류 위치 2차원 배열(nuts)을 매개변수로 받습니다.
  3. 누적 거리 ret은 0으로, 최대 절약량 maxDiff는 음의 무한대(-∞)로 초기화합니다.
  4. 모든 견과류 i에 대해 다음을 반복합니다.
    • dist := 나무와 i번째 견과류 사이의 거리를 계산합니다.
    • ret := ret + 2 × dist (왕복 거리를 누적합니다.)
    • maxDiff := max(maxDiff, 2 × dist − (dist + 다람쥐와 해당 견과류 사이의 거리)) — 이 값이 바로 해당 견과류를 첫 번째로 가져갈 때 절약되는 거리입니다.
  5. ret − maxDiff를 반환합니다. 이것이 곧 최소 이동 거리입니다.

이 알고리즘의 시간 복잡도는 견과류 개수를 N이라 할 때 O(N)이며, 추가 메모리 없이 상수 공간 O(1)로 해결할 수 있습니다.

C++ 구현 예제

아래 코드를 통해 동작 방식을 더 잘 이해할 수 있습니다.

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    int calc(int x1, int y1, int x2, int y2){
        return abs(x1 - x2) + abs(y1 - y2);
    }
    int minDistance(int height, int width, vector<int>& tree, vector<int>& sq, vector<vector<int>>& nuts) {
        int ret = 0;
        int maxDiff = INT_MIN;
        for (int i = 0; i < nuts.size(); i++) {
            int dist = calc(tree[0], tree[1], nuts[i][0], nuts[i][1]);
            ret += 2 * dist;
            maxDiff = max(maxDiff, 2 * dist - (dist + calc(nuts[i][0], nuts[i][1], sq[0], sq[1])));
        }
        return ret - maxDiff;
    }
};
main(){
    Solution ob;
    vector<int> v = {2,2}, v1 = {4,4};
    vector<vector<int>> v2 = {{3,0}, {2,5}};
    cout << (ob.minDistance(5,7,v, v1, v2));
}

입력

5, 7, {2,2},{4,4}, {{3,0}, {2,5}}

출력

12

결과 분석

나무 [2,2]에서 견과류 [3,0]까지의 거리는 3, 견과류 [2,5]까지의 거리 역시 3입니다. 모든 견과류를 나무 기준 왕복으로 옮기면 3 × 2 + 3 × 2 = 12가 됩니다.

이제 첫 이동을 다람쥐 위치에서 시작할 때의 절약량을 살펴보겠습니다. 절약량은 "나무→견과류 거리 − 다람쥐→견과류 거리"로 계산됩니다.

  • 견과류 [2,5]: 3 − 3 = 0
  • 견과류 [3,0]: 3 − 5 = −2 (오히려 손해)

따라서 최대 절약량 maxDiff는 0이 되고, 최종 답은 12 − 0 = 12입니다. 다람쥐가 [2,5]를 먼저 가져간 뒤 [3,0]을 처리하는 것이 최적 경로임을 알 수 있습니다.