danbibibi
article thumbnail

문제

문제 바로가기> BOJ 1938번: 통나무 옮기기

 

1938번: 통나무 옮기기

첫째 줄에 주어진 평지의 한 변의 길이 N이 주어진다. (4 ≤ N ≤ 50) 주어진다. 이어서 그 지형의 정보가 0, 1, B, E로 이루어진 문자열로 주어진다. 한 줄에 입력되는 문자열의 길이는 N이며 입력 문

www.acmicpc.net

 

풀이

최소 동작 횟수를 구하는 것이기 때문에 bfs를 이용했다.

또한 한 지점에서 통나무의 모양이 ㅡ(가로) 또는 ㅣ(세로) 일 수 있기 때문에 visited 배열을 3차원으로 선언해주었다!

코드가 지저분해서,, 언제 한번 다시 깔끔하게 짜보아야겠다 ,,

#include<iostream>
#include<queue>
#define MAX 55
#define SIZE 3
using namespace std;

struct POS{
    int y, x;
} start[SIZE], dest[SIZE];

struct QUEUE{
    POS tree[SIZE];
    int cnt, dir;
};

int N;
char map[MAX][MAX];
bool visited[MAX][MAX][2];
int dy[] = {-1, 1, 0, 0};
int dx[] = {0, 0, -1, 1};

void input(){
    cin >> N;
    int sidx=0, didx=0;
    for (int i = 0; i < N; i++){
        for (int j = 0; j < N; j++){
            cin >> map[i][j];
            if(map[i][j] == 'B'){ // 통나무
                start[sidx++] = {i, j};
                map[i][j] = '0';
            }
            if(map[i][j] == 'E'){ // 도착지
                dest[didx++] = {i, j};
                map[i][j] = '0';
            }
        }
    }
}

int bfs(){
    
    // 1. 시작점및 방문 처리
    queue<QUEUE> q;
    QUEUE tmp;
    tmp.tree[0] = start[0];
    tmp.tree[1] = start[1];
    tmp.tree[2] = start[2];
    tmp.cnt = 0;
    tmp.dir = 0;
    q.push(tmp);
    if(start[0].y == start[1].y) { // 'ㅡ' 모양
        visited[start[0].y][start[0].x][0] = true;
    }
    else { // 'ㅣ' 모양
        q.front().dir = 1;
        visited[start[0].y][start[0].x][1] = true;
    }
    

    // 2. bfs
    while (!q.empty()){

        tmp = q.front();
        q.pop();

        // 도착했는 지 확인
        bool isArrive = true;
        for (int i = 0; i < SIZE; i++){
            if(tmp.tree[i].y!=dest[i].y || tmp.tree[i].x!=dest[i].x)
                isArrive = false;
        }

        // 도착한 경우
        if(isArrive) return tmp.cnt;

        // 상하좌우 이동
        for (int d = 0; d < 4; d++){
            
            QUEUE ntmp;
            ntmp.dir = tmp.dir;
            ntmp.cnt = tmp.cnt + 1;

            // 이동 가능한지 확인 및 이동
            bool isMove=true;
            for (int i = 0; i < SIZE; i++){
                int ny = tmp.tree[i].y + dy[d];
                int nx = tmp.tree[i].x + dx[d];
                ntmp.tree[i] = {ny, nx};
                if(ny<0 || ny >=N || nx<0 || nx>=N) {isMove=false; continue;} // 범위를 벗어난 경우
                if(map[ny][nx] == '1') {isMove=false; continue;} // 다른 나무가 있는 경우
            }
            if(!isMove || visited[ntmp.tree[0].y][ntmp.tree[0].x][ntmp.dir]) continue;
            visited[ntmp.tree[0].y][ntmp.tree[0].x][ntmp.dir] = true;
            q.push(ntmp);
        }

        // 회전 이동
        QUEUE ntmp;
        ntmp.dir = 1 - tmp.dir;
        ntmp.cnt = tmp.cnt + 1;
        if(tmp.dir == 0){ // 현재 가로(ㅡ)인 경우
            bool isMove=true;
            for (int i = 0; i < SIZE; i++){
                POS up = {tmp.tree[i].y-1, tmp.tree[i].x};
                POS down = {tmp.tree[i].y+1, tmp.tree[i].x};
                if(up.y<0 || up.y>=N || down.y<0 || down.y>=N || up.x<0 || up.x>=N) isMove=false; // 범위를 벗어난 경우
                if(map[up.y][up.x]=='1' || map[down.y][down.x]=='1') isMove=false; // 다른 나무가 있는 경우
            }
            if(isMove){
                ntmp.tree[0] = {tmp.tree[1].y-1, tmp.tree[1].x};
                ntmp.tree[1] = {tmp.tree[1].y, tmp.tree[1].x};
                ntmp.tree[2] = {tmp.tree[1].y+1, tmp.tree[1].x};
                if(!visited[ntmp.tree[0].y][ntmp.tree[0].x][ntmp.dir]){
                    visited[ntmp.tree[0].y][ntmp.tree[0].x][ntmp.dir] = true;
                    q.push(ntmp);
                }
            }
        }
        else{ // 현재 세로(ㅣ)인 경우
            bool isMove=true;
            for (int i = 0; i < SIZE; i++){
                POS left = {tmp.tree[i].y, tmp.tree[i].x-1};
                POS right = {tmp.tree[i].y, tmp.tree[i].x+1};
                if(left.y<0 || left.y>=N || left.x<0 || left.x>=N || right.x<0 || right.x>=N) isMove=false; // 범위를 벗어난 경우
                if(map[left.y][left.x]=='1' || map[right.y][right.x]=='1') isMove=false; // 다른 나무가 있는 경우
            }
            if(isMove){
                ntmp.tree[0] = {tmp.tree[1].y, tmp.tree[1].x-1};
                ntmp.tree[1] = {tmp.tree[1].y, tmp.tree[1].x};
                ntmp.tree[2] = {tmp.tree[1].y, tmp.tree[1].x+1};
                if(!visited[ntmp.tree[0].y][ntmp.tree[0].x][ntmp.dir]){
                    visited[ntmp.tree[0].y][ntmp.tree[0].x][ntmp.dir] = true;
                    q.push(ntmp);
                }
            }
        }
    }
    
    return 0; // 이동 불가능한 경우
}

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    input();
    cout << bfs();
}

'문제 풀이 > 백준' 카테고리의 다른 글

BOJ 5719번: 거의 최단 경로  (0) 2024.02.21
BOJ 12851번: 숨바꼭질 2  (0) 2024.02.21
BOJ 1005번: ACM Craft  (0) 2024.02.18
BOJ 1477번: 휴게소 세우기  (0) 2024.02.11
BOJ 2933번: 미네랄  (0) 2024.01.31
profile

danbibibi

@danbibibi

꿈을 꾸는 시간은 멈춰 있는 것이 아냐 두려워하지 마 멈추지 마 푸른 꿈속으로