본문 바로가기

Tech/Problem Solving

[백준 2206] 벽 부수고 이동하기 (Java)

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

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다. 만약에 이동하는 도중에 한 개의 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 한 개 까지 부수고 이동

www.acmicpc.net

접근 방법

bfs를 이용해 풀어야하는 문제이지만

1번 벽을 부수고 이동이 가능하다는 특징이 있었다.

벽을 단 한번만 부술 수 있기 때문에 이를 체크하면서 이동해야한다. 벽을 부순 상태를 남겨 이미 부쉈다면 벽을 지나갈 수 없도록 만들어야한다.

 

일반적인 bfs와 다르게 boolean 타입의 2차원 배열을 이용해서 방문을 체크하는 방법은 시간을 초과한다. 대신 3차원 배열을 만들고 3차원 째 배열의 크기를 2로 두어 벽이 부순 상태가 아닌 경우와 벽이 부순 상태의 경우를 나눠서 방문을 체크해야했다.

(이 부분에 대해서는 이유를 찾지 못했다. 학습이 더 필요한 부분이다.)

 

소스 코드

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	// 상,하,좌,우 이동시키기 위한 배열
    private static int[] x = {1, 0, -1, 0};
    private static int[] y = {0, 1, 0, -1};
    
    private static int N;
    private static int M;
    private static int[][] map;
    
    // 방문 여부를 체크
    private static boolean[][][] isVisited;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        N = scanner.nextInt();
        M = scanner.nextInt();
        map = new int[N + 1][M + 1];
        
        // isVisited[x][y][0] -> 벽이 부숴진 상태가 아닌 경우 방문 여부
        // isVisited[x][y][1] -> 벽이 부숴진 상태인 경우 방문 여부
        isVisited = new boolean[N + 1][M + 1][2];

        scanner.nextLine();
        for (int i = 1; i <= N; i++) {
            String[] input = scanner.nextLine().split("");
            for (int j = 1; j <= M; j++) {
                map[i][j] = Integer.parseInt(input[j - 1]);
            }
        }

        bfs(1, 1);
    }

    private static void bfs(int px, int py) {
        Queue<Point> queue = new LinkedList<>();

        queue.add(new Point(px, py, 1, 0));
        isVisited[px][py][0] = true;
        isVisited[px][py][1] = true;

        while (!queue.isEmpty()) {
            Point point = queue.poll();

            if (point.px == N && point.py == M) {
                System.out.println(point.depth);
                return;
            }

			// 상하좌우 순차적으로 탐색
            for (int i = 0; i < 4; i++) {
                int newX = point.px + x[i];
                int newY = point.py + y[i];

				// 주어진 N*M 사이즈를 벗어나지 않는지
                if (newX > 0 && newX <= N && newY > 0 && newY <= M) {
                	// 방문한 위치가 벽인 경우
                    if (map[newX][newY] == 1) {
                    	// 벽을 부수지 않았는지 && 벽을 부수지 않았은 경우 방문 안했는지
                        if (point.used == 0 && !isVisited[newX][newY][1]) {
                            queue.add(new Point(newX, newY, point.depth + 1, 1));
                            isVisited[newX][newY][1] = true;
                        }
                    } else {
                    	// 방문한 위치가 벽이 아닌경우
                        // 방문한 이력이 없는지
                        if (!isVisited[newX][newY][point.used]) {
                            queue.add(new Point(newX, newY, point.depth + 1, point.used));
                            isVisited[newX][newY][point.used] = true;
                        }
                    }
                }
            }
        }

        System.out.println(-1);
    }

    private static class Point {
        private int px;
        private int py;
        private int depth;
        private int used;

        Point(int x, int y, int depth, int used) {
            this.px = x;
            this.py = y;
            this.depth = depth;
            this.used = used;
        }
    }
}
반응형

'Tech > Problem Solving' 카테고리의 다른 글

[백준 7569] 토마토 (Java)  (0) 2020.02.25
[백준 7576] 토마토 (Java)  (0) 2020.02.25
[백준 2579] 계단 오르기 (Java)  (0) 2020.02.21
[백준 1463] 1로 만들기 (Java)  (0) 2020.02.21
[백준 1003] 피보나치 함수 (Java)  (0) 2020.02.21