쾌락없는 책임 (공부)/알고리즘 문제풀이

[Algorithm] 백준 1600 말이 되고픈 원숭이 - C++, BFS

허스크 2022. 5. 16. 10:07
반응형
 

1600번: 말이 되고픈 원숭이

첫째 줄에 정수 K가 주어진다. 둘째 줄에 격자판의 가로길이 W, 세로길이 H가 주어진다. 그 다음 H줄에 걸쳐 W개의 숫자가 주어지는데, 0은 아무것도 없는 평지, 1은 장애물을 뜻한다. 장애물이 있

www.acmicpc.net

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;

int moveY[] = { 0, 0, 1, -1 };
int moveX[] = { 1, -1, 0, 0 };
pair<int, int> horseMove[] = { {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}, 
                               {1, -2}, {2, -1}, {2, 1}, {1, 2} };
int k, w, h;
int map[201][201];
bool visit[201][201][31];

bool IsOut(int y, int x){
    if(x < 0 || y < 0 || x >= w || y >= h)
        return true;
    if(map[y][x] == 1)
        return true;
    return false;
}

bool SearchCount(){
    queue<pair<pair<int, int>, pair<int, int>>> q;
    q.push({{0, 0}, {0, 0}});

    while(!q.empty()){
        int curK = q.front().first.first;
        int curCount = q.front().first.second;
        int curY = q.front().second.first;
        int curX = q.front().second.second;
        q.pop();

        // if now on finish
        if(curY == h-1 && curX == w-1){
            cout << curCount << '\n';
            return true;
        }

        // can horse movement
        if(curK < k){
            for(int i = 0; i < 8; i++){
                int nextY = curY + horseMove[i].first;
                int nextX = curX + horseMove[i].second;

                if(IsOut(nextY, nextX)) continue;
                if(visit[nextY][nextX][curK+1]) continue;

                q.push({{curK+1, curCount+1}, {nextY, nextX}});
                visit[nextY][nextX][curK+1] = true;
            }
        }

        // normal movement
        for(int i = 0; i < 4; i++){
            int nextY = curY + moveY[i];;
            int nextX = curX + moveX[i];

            if(IsOut(nextY, nextX)) continue;
            if(visit[nextY][nextX][curK]) continue;

            q.push({{curK, curCount+1}, {nextY, nextX}});
            visit[nextY][nextX][curK] = true;  
        }
    }

    return false;
}

int main(){
    // init
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    // input
    cin >> k;
    cin >> w >> h;
    for(int i = 0; i < h; i++){
        for(int j = 0; j < w; j++){
            cin >> map[i][j];
        }
    }

    if(!SearchCount())
        cout << -1 << '\n';
}

 NC 코테에서 쉬워보이는 BFS를 풀지 못했다는 아쉬움에 풀게 된 BFS 문제입니다. 기존의 4방향으로 이동하던 단순 BFS 와는 달리 8방향이 추가되어 총 12개 방향으로 갈 수 있게 된 문제입니다. 대신 추가된 8개 방향은 K번만 이동할 수 있어 이에 대한 제약조건이 필요한 문제였습니다.

queue<pair<pair<int, int>, pair<int, int>>> q;

 일단 큐에 <현재 말처럼 이동한 횟수, 현재 이동 횟수>, <Y, X> 를 넣어주면서 계산을 했고

        // can horse movement
        if(curK < k){
            for(int i = 0; i < 8; i++){
                int nextY = curY + horseMove[i].first;
                int nextX = curX + horseMove[i].second;

                if(IsOut(nextY, nextX)) continue;
                if(visit[nextY][nextX][curK+1]) continue;

                q.push({{curK+1, curCount+1}, {nextY, nextX}});
                visit[nextY][nextX][curK+1] = true;
            }
        }

        // normal movement
        for(int i = 0; i < 4; i++){
            int nextY = curY + moveY[i];;
            int nextX = curX + moveX[i];

            if(IsOut(nextY, nextX)) continue;
            if(visit[nextY][nextX][curK]) continue;

            q.push({{curK, curCount+1}, {nextY, nextX}});
            visit[nextY][nextX][curK] = true;  
        }

 이후 K횟수가 남았는지를 체크하면서 남았다면 말의 움직임을 해보고 아니면 하지 않는 방식으로 했습니다. 이렇게 기존 BFS 에 K 추가만 넣으면 쉽게 풀이할 수 있는 문제였습니다.

반응형