image

백준 2206: 벽 부수고 이동하기

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

풀이

  • 기본적으로 bfs로 풀이
  • 벽을 부수는 경우와 안 부수는 경우가 있다.
  • 방문 처리를 벽을 한번 부순 경우 / 부수지 않은 경우로 나누어서 진행
  • 가장 빠르게 목적지에 도달하면 종료
package algorithm2024.feb.day19;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class BOJ_2206_벽부수고이동하기 {
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StringTokenizer st;
	static StringBuilder sb = new StringBuilder();

	//방향벡터 dy, dx 상 우 하 좌 순
	static int[] dy = {-1, 0, 1, 0};
	static int[] dx = {0, 1, 0, -1};

	//행의 개수 N, 열의 개수 M, N*M 맵
	static int N, M, map[][];

	//방문처리 boolean 배열, N*M*2
	static boolean[][][] v;

	//정답을 담을 변수
	static int ans = -1;

	//bfs를 위한 노드 클래스, 위치 좌표 y,x 와 움직인 거리 l, 벽을 부순 적이 있는지 여부를 나타내는 isBreak 변수를 두었다.
	static class Node {
		int y, x, l;
		boolean isBreak;

		public Node(int y, int x, int l, boolean isBreak) {
			this.y = y;
			this.x = x;
			this.l = l;
			this.isBreak = isBreak;
		}

	}

	//Node가 올바른 자리에 있는지 확인하는 함수, 범위를 벗어나면 false 리턴
	static boolean isValid(Node node) {
		int y = node.y;
		int x = node.x;

		if (y < 0 || x < 0 || y >= N || x >= M)
			return false;
		return true;
	}

	public static void main(String[] args) throws Exception {
		st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());

		map = new int[N][M];
		v = new boolean[N][M][2];

		for (int i = 0; i < N; i++) {
			String[] s = br.readLine().split("");
			for (int j = 0; j < M; j++) {
				map[i][j] = Integer.parseInt(s[j]);
			}
		}

		/*여기까지 입력*/

		//bfs를 위해 큐 사용
		Queue<Node> q = new LinkedList<>();
		q.add(new Node(0, 0, 1, false));
		v[0][0][0] = true;

		/*bfs*/
		while (!q.isEmpty()) {

			Node cur = q.poll();
			int y = cur.y;
			int x = cur.x;
			int l = cur.l;
			/*목적지에 도착하면 종료*/
			if (y == N - 1 && x == M - 1) {
				ans = l;
				break;
			}
			boolean isBreak = cur.isBreak;
			/*방향벡터 돌려보면서 확인*/
			for (int d = 0; d < 4; d++) {
				int ny = y + dy[d];
				int nx = x + dx[d];
				Node next = new Node(ny, nx, l + 1, isBreak);
				/*범위를 벗어나면 continue*/
				if (!isValid(next))
					continue;
				/*다음 경로가 벽이고 아직 벽을 부순 적이 없다면*/
				if (map[ny][nx] == 1 && !isBreak && !v[ny][nx][1]) {
					v[ny][nx][1] = true;
					next.isBreak = true;
					q.offer(next);
					/*다음 목적지가 벽이 아님*/
				} else if (map[ny][nx] == 0) {
					/*벽으 부순 적이 있는데 이미 벽을 부수고 해당 목적지로 간 적이 있으면 continue*/
					if (isBreak) {
						if (v[ny][nx][1])
							continue;
						v[ny][nx][1] = true;
						/*벽을 부순 적이 없지만 해당 목적지에 이미 간 적이 있으면 continue*/
					} else {
						if (v[ny][nx][0])
							continue;
						v[ny][nx][0] = true;
					}
					q.offer(next);
				}
			}
		}
		System.out.println(ans);

	}
}


Issue

  • 처음에 DFS로 풀었는데 시간 초과 떴음.
  • 최단 경로를 찾는 문제는 bfs가 훨씬 빠름!

Leave a comment