danbibibi
article thumbnail

문제

문제 바로가기> BOJ 2206번: 벽 부수고 이동하기

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로

www.acmicpc.net

 

풀이

벽을 하나씩 제거 + BFS 하는 경우, O(N^2*M^2)으로 시간 초과가 발생한다.

 

생각해보면, 어느 지점(y, x)에 도착할 때,

남은 기회가 있거나 or 없거나 둘 중 하나의 상태로 도착할 것이다.

이 점을 이용해서 BFS 탐색을 진행하면, BFS를 한번만 돌려도 문제를 풀수 있다!

 

추가로, 가중치가 동일할 때 최단 경로를 찾는 문제이므로,

가장 먼저 (N-1, M-1)에 도착했을 때의 dist를 반환해주면 된다!

 

C++

#include<iostream>
#include<vector>
#include<queue>
#define INF 100000001
#define MAX 1001
#define WALL 1
#define EMPTY 0
using namespace std;

struct DATA { int y, x, chance; };

int N, M;
int map[MAX][MAX];
int dist[MAX][MAX][2];
int dy[] = { -1, 1, 0, 0 };
int dx[] = { 0, 0, -1, 1 };

void input() {
	cin >> N >> M;
	for (int i = 0; i < N; i++) {
		string str; cin >> str;
		for (int j = 0; j < M; j++) map[i][j] = str[j] - '0';
	}
}

int solution() {
	queue<DATA> q;
	q.push({ 0,0,1 }); // (0,0)에서 출발, 벽을 꺨 수 있는 기회 한번
	dist[0][0][1] = 1;

	while (!q.empty()) {
		int y = q.front().y;
		int x = q.front().x;
		int chance = q.front().chance;
		q.pop();

		if(y==N-1 && x==M-1) return dist[y][x][chance]; // 도착한 경우
		for(int d=0; d<4; d++){
			int ny = y+dy[d];
			int nx = x+dx[d];
			if(ny<0 || ny>=N || nx<0 || nx>=M || dist[ny][nx][chance]) continue; // 범위를 벗어나는 경우, 이미 방문한 경우
			if(map[ny][nx]==WALL && chance){ // 벽인데, 남은 기회가 있는 경우
				dist[ny][nx][0] = dist[y][x][1]+1;
				q.push({ny, nx, 0});
			}
			else if(map[ny][nx]==EMPTY){ // 벽이 아닌 경우
				dist[ny][nx][chance] = dist[y][x][chance]+1;
				q.push({ny, nx, chance});
			}
		}
	}
	return -1; // 도착 불가능한 경우
}

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

 

JAVA

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

public class Main {
	
	static final int[] dy = {-1, 1, 0, 0};
	static final int[] dx = {0, 0, -1, 1};

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		int M = Integer.parseInt(st.nextToken());
		
		int[][][] dist = new int[N][M][2];
		boolean[][] map = new boolean[N][M];
		
		for(int i=0; i<N; i++) {
			String line = br.readLine();
			for(int j=0; j<M; j++) map[i][j] = (line.charAt(j)=='0'?false:true);
		}
		
		ArrayDeque<int[]> q = new ArrayDeque<>();
		q.offer(new int[]{0, 0, 1});
		dist[0][0][1] = 1;
		
		while(!q.isEmpty()) {
			int y = q.peek()[0];
			int x = q.peek()[1];
			int c = q.peek()[2];
			q.poll();
			
			if(y==N-1 && x==M-1) {
				System.out.println(dist[y][x][c]);
				return;
			}
			
			for(int d=0; d<4; d++) {
				int ny = y+dy[d];
				int nx = x+dx[d];
				if(ny<0 || ny>=N || nx<0 || nx>=M || dist[ny][nx][c]>0) continue;
				if(map[ny][nx] && c==1) { // wall
					dist[ny][nx][0] = dist[y][x][1]+1;
					q.offer(new int[] {ny, nx, 0});
				}
				else if(!map[ny][nx]) { // empty
					dist[ny][nx][c] = dist[y][x][c]+1;
					q.offer(new int[] {ny, nx, c});
				}
			}
		}
		System.out.println(-1);
		br.close();
	}
}

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

BOJ 17070번: 파이프 옮기기1  (1) 2023.01.25
BOJ 17406번: 배열 돌리기 4  (0) 2023.01.19
BOJ 15663번: N과 M (9)  (0) 2023.01.15
BOJ 2573번: 빙산  (0) 2022.12.31
BOJ 11057번: 오르막 수  (0) 2022.12.30
profile

danbibibi

@danbibibi

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