[백준] 16933번 벽 부수고 이동하기 3 Java

JeongYong·2022년 11월 3일
0

Algorithm

목록 보기
54/275

문제 링크

https://www.acmicpc.net/problem/16933

알고리즘: BFS

문제

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다. 이동하지 않고 같은 칸에 머물러있는 경우도 가능하다. 이 경우도 방문한 칸의 개수가 하나 늘어나는 것으로 생각해야 한다.

이번 문제에서는 낮과 밤이 번갈아가면서 등장한다. 가장 처음에 이동할 때는 낮이고, 한 번 이동할 때마다 낮과 밤이 바뀌게 된다. 이동하지 않고 같은 칸에 머무르는 경우에도 낮과 밤이 바뀌게 된다.

만약에 이동하는 도중에 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 K개 까지 부수고 이동하여도 된다. 단, 벽은 낮에만 부술 수 있다.

한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.

맵이 주어졌을 때, 최단 경로를 구해 내는 프로그램을 작성하시오.

풀이

이 문제는 벽 부수고 이동하기 2문제와 유사하지만 다른 점은 밤에 벽을 부술 수 없다는 것이다.
이 점만 유의하면 매우 쉽게 풀 수 있다. 이 문제를 풀기 전에 벽 부수고 이동하기 2를 풀지 않았다면 풀고 오길 추천한다. 벽을 만났을 경우만 다르게 처리해주면 되는데 벽을 만났을 경우에 낮이면 그대로 처리해주고, 밤인 경우는 칸에 머무를 수밖에 없다. 그렇기 때문에 x,y,k는 그대로 값을 가져가고 머무르는 경우도 카운트하라고 문제에 명시돼있으니 c + 1, 밤이기 때문에 낮에 해당하는 값인 0값을 넣어준다.
그러면 que에 들어갈 값은 (x,y,k,c+1,0)이다. 이 경우만 처리해준다면 통과할 수 있다.

소스코드

import java.io.*;
import java.util.*;

class Node {
    int x,y,k,c,an;
    Node(int x, int y, int k, int c, int an) {
        //an => 낮, 밤 구분 낮은 0, 밤은 1
        this.x = x;
        this.y = y;
        this.k = k;
        this.c = c;
        this.an = an;
    }
}
public class Main {
    static final int dx[] = {0,0,-1,1};
    static final int dy[] = {-1,1,0,0};
    static int map[][];
    static int visited_min[][];
    static int N, M, K;
    public static void main(String args[])throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        
        map = new int[N][M];
        visited_min = new int[N][M];
        for(int i=0; i<N; i++) {
            String s = br.readLine();
            Arrays.fill(visited_min[i], K+1);
            for(int j=0; j<M; j++) {
                map[i][j] = s.charAt(j) - '0';
            }
        }
        System.out.println(BFS());
    }
    
    static int BFS() {
        Queue<Node> que = new LinkedList<>();
        que.add(new Node(0,0,0,1,0));
        while(!que.isEmpty()) {
            Node v = que.poll();
            if(v.x == M-1 && v.y == N-1) {
                return v.c;
            }
            for(int i=0; i<4; i++) {
                int nx = v.x + dx[i];
                int ny = v.y + dy[i];
                if((nx>=0 && nx<=M-1) && (ny>=0 && ny<=N-1)) {
                    if(map[ny][nx] == 0) {
                        if(visited_min[ny][nx] > v.k) {
                            visited_min[ny][nx] = v.k;
                            int af_ni = (v.an == 0) ? 1 : 0;
                            que.add(new Node(nx, ny, v.k, v.c+1, af_ni));
                        }
                    } else {
                        //벽을 만났을때
                        if(v.an == 0) {
                            //현재 낮이면.
                            if(visited_min[ny][nx] > v.k+1) {
                                visited_min[ny][nx] = v.k+1;
                                que.add(new Node(nx, ny, v.k+1, v.c+1, 1));
                            }
                        } else {
                            //현재 밤이면. 칸에 머물러있는 경우 밖에 없음.
                            que.add(new Node(v.x, v.y, v.k, v.c+1, 0));
                        }
                    }
                }
            }
        }
        return -1;
    }
}

0개의 댓글