상인과 수행원 강 건너기 문제의 DFS 알고리즘 구현

문제 정의

세 명의 상인과 각각 한 명의 수행원이 강을 건너야 한다. 작은 배는 최대 두 사람만 탑승할 수 있으며, 상인들이 직접 조종해야 한다. 강의 어느 쪽이든 수행원 수가 상인 수보다 많아지면 상인들을 해칠 계획이다. 상인들이 안전하게 강을 건너려면 어떻게 해야 할까?

수학적 모델링

이 문제를 해결하기 위해 깊이 우선 탐색(DFS) 알고리즘을 적용한다. 선박의 적재 용량이 2명일 때 가능한 모든 이동 상태와 상인과 수행원의 안전한 수치 조합을 미리 정의한다. 탐색 과정에서 경로를 기록하며, 왼쪽 강변에 아무도 남지 않은 상태를 찾으면 즉시 탐색을 종료하고 해결책을 출력한다.

변수 정의

Path: 단계별 경로를 저장하는 배열
PossibleMoves: 가능한 이동 방법들을 정의
SafetyCheck: 현재 상태의 안전 여부를 판단
VesselPosition: 현재 배의 위치(건너감 또는 돌아옴)

실행 결과

총 11단계로 해결 가능

  • 1단계: 수행원 두 명이 건넌다
  • 2단계: 수행원 한 명이 다시 돌아온다
  • 3단계: 수행원 두 명이 다시 건넌다
  • 4단계: 수행원 한 명이 다시 돌아온다
  • 5단계: 상인 두 명이 건넌다
  • 6단계: 수행원 한 명과 상인 한 명이 돌아온다
  • 7단계: 상인 두 명이 건넌다
  • 8단계: 수행원 한 명이 돌아온다
  • 9단계: 수행원 두 명이 건넌다
  • 10단계: 수행원 한 명이 돌아온다
  • 11단계: 마지막으로 수행원 두 명이 건넌다

C++ 구현 코드

#include <bits/stdc++.h>
using namespace std;

const int PossibleMoves[5][2] = {{0, 2}, {1, 1}, {2, 0}, {0, 1}, {1, 0}};
const bool SafetyCheck[4][4] = {{0, 0, 0, 0}, {1, 0, 1, 1}, {1, 1, 0, 1}, {0, 0, 0, 0}};

int Path[1001][2], currentStep = 1;
bool VesselPosition[1001], solutionFound = false;

bool hasDuplicate(int merchants, int servants, bool position) {
    for(int idx = 0; idx < currentStep; idx++) {
        if(merchants == Path[idx][0] && servants == Path[idx][1] && VesselPosition[idx] == position) 
            return true;
    }
    return false;
}

bool isUnsafe(int traders, int attendants, bool position) {
    if (traders < 0 || traders > 3 || attendants < 0 || attendants > 3 || SafetyCheck[traders][attendants] || hasDuplicate(traders, attendants, position)) 
        return true;
    return false;
}

void exploreSolution(int merchantCount, int servantCount) {
    if(!merchantCount && !servantCount) {
        cout << currentStep - 1 << endl;
        cout << "(왼쪽상인,왼쪽수행)" << " " << "(오른쪽상인,오른쪽수행)" << endl;
        for (int idx = 0; idx < currentStep; idx++) {
            cout << "(" << Path[idx][0] << "," << Path[idx][1] << ") ";
            cout << "(" << 3 - Path[idx][0] << "," << 3 - Path[idx][1] << ")" << endl;
        }
        exit(0);
    }
    else if (!solutionFound) {
        for (int moveIdx = 0; moveIdx <= 4; moveIdx++) {
            merchantCount -= PossibleMoves[moveIdx][0];
            servantCount -= PossibleMoves[moveIdx][1];
            
            if (isUnsafe(merchantCount, servantCount, solutionFound)) {
                merchantCount += PossibleMoves[moveIdx][0];
                servantCount += PossibleMoves[moveIdx][1];
                continue;
            }
            
            Path[currentStep][0] = merchantCount;
            Path[currentStep][1] = servantCount;
            VesselPosition[currentStep] = solutionFound;
            
            currentStep++;
            solutionFound = (!solutionFound);
            exploreSolution(merchantCount, servantCount);
            solutionFound = (!solutionFound);
            
            merchantCount += PossibleMoves[moveIdx][0];
            servantCount += PossibleMoves[moveIdx][1];
            currentStep--;
        }
    }
}

int main() {
    Path[0][0] = Path[0][1] = 3;
    VesselPosition[0] = true;
    exploreSolution(3, 3);
    return 0;
}

Python 구현 코드

PossibleMoves = [(0, 2), (1, 1), (2, 0), (0, 1), (1, 0)]
SafetyCheck = [[0, 0, 0, 0], [1, 0, 1, 1], [1, 1, 0, 1], [0, 0, 0, 0]]

Path = [[0, 0] for _ in range(1001)]
VesselPosition = [False] * 1001
currentStep = 1
solutionFound = False

def hasDuplicate(merchants, servants, position):
    for idx in range(currentStep):
        if merchants == Path[idx][0] and servants == Path[idx][1] and VesselPosition[idx] == position:
            return True
    return False

def isUnsafe(traders, attendants, position):
    if traders < 0 or traders > 3 or attendants < 0 or attendants > 3 or SafetyCheck[traders][attendants] or hasDuplicate(traders, attendants, position):
        return True
    return False

def exploreSolution(merchantCount, servantCount):
    global currentStep, solutionFound
    
    if not merchantCount and not servantCount:
        print(currentStep - 1)
        print("(왼쪽상인, 왼쪽수행) (오른쪽상인, 오른쪽수행)")
        for idx in range(currentStep):
            print(f"({Path[idx][0]}, {Path[idx][1]}) ({3 - Path[idx][0]}, {3 - Path[idx][1]})")
        exit(0)
    
    if not solutionFound:
        for moveIdx in range(5):
            merchantCount -= PossibleMoves[moveIdx][0]
            servantCount -= PossibleMoves[moveIdx][1]
            
            if isUnsafe(merchantCount, servantCount, solutionFound):
                merchantCount += PossibleMoves[moveIdx][0]
                servantCount += PossibleMoves[moveIdx][1]
                continue
            
            Path[currentStep][0] = merchantCount
            Path[currentStep][1] = servantCount
            VesselPosition[currentStep] = solutionFound
            
            currentStep += 1
            solutionFound = not solutionFound
            exploreSolution(merchantCount, servantCount)
            solutionFound = not solutionFound
            
            merchantCount += PossibleMoves[moveIdx][0]
            servantCount += PossibleMoves[moveIdx][1]
            currentStep -= 1

if __name__ == "__main__":
    Path[0][0] = Path[0][1] = 3
    VesselPosition[0] = True
    exploreSolution(3, 3)

태그: algorithm dfs graph-traversal cpp python

8월 8일 18:46에 게시됨