KDHzoot's Github

Code for study, project, etc

자세히보기

알고리즘/PS

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

kdhzoot 2020. 8. 21. 00:23

문제 링크 : https://www.acmicpc.net/problem/2206

 

2206번: 벽 부수고 이동하기

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

www.acmicpc.net

bfs를 이용한 탐색 문제이다

 

기존의 탐색에서 벽을 한번 부수고 이동할 수 있다는 조건이 붙었기 때문에

 

구현하는데 어려움이 생겼다


이럴경우 각 좌표까지 최단거리를 두가지 상황으로 정리하면 쉽게 풀 수 있다

 

1. 벽을 뚫지 않고 격자까지 이동한 경우

 

2. 벽을 한번 뚫고 격자까지 이동한 경우

 

1번의 경우 벽이 없는 길로 1을 갱신하거나

 

벽을 뚫으면서 2의 최단거리를 갱신할 수 있지만

 

2번은 벽이 없는 길로 2번만 갱신할 수 있다.


bfs에 dp를 살짝 섞은 문제라고 볼 수 있다

 

#include <stdio.h>
#include <algorithm>
#include <queue>
#define n_ 1000 + 10
using namespace std;

char adj[n_][n_];
// x, y까지 최단경로를 저장하는 배열
// 여기서 마지막이 [x][y][0]이면 벽을 뚫은적 없이 이동했을 때 최단경로
// [x][y][1]이면 벽을 한번 뚫고 이동했을 대 최단경로
int dp[n_][n_][2];
int dx[4] = { 0, 1, 0, -1 };
int dy[4] = { 1, 0, -1, 0 };
int n, m;
// 변수 k는 x,y까지 올 때 벽을 뚫었는지 안뚫었는지 여부이다
// 안뚫었으면 0, 뚫었으면 1
typedef struct Node {
	int x, y, k;
}node;

queue<node> q;

void bfs() {
	// 시작은 0, 0에서 벽을 뚫지 않은 상태로
	q.push({ 0, 0, 0 });
	dp[0][0][0] = 1;

	while (!q.empty()) {
		node now = q.front();
		q.pop();

		int a = now.x;
		int b = now.y;
		int c = now.k;
		
		// 상하좌우 탐색
		for (int i = 0; i < 4; i++) {
			int nx = a + dx[i];
			int ny = b + dy[i];
			// 격자 밖이면 무시
			if (nx == -1 || nx == n || ny == -1 || ny == m) continue;

			// 식이 복잡하지만 adj[nx][ny]가 '1'일때와 '0'일때 따로 생각하면 편함
			// adj[nx][ny]가 '1', 벽일 경우 c가 1 증가. 벽이면 뚫고 이동할 것이기 때문
			// adj[nx][ny]가 '0', 벽이 아닐 경우 c는 그대로. 딱히 벽 안뚫고 그대로 이동
			int nk = adj[nx][ny] - '0' + c;

			// 벽을 이미 뚫었으면, 지금 뚫는 벽이 두번째라면 불가
			if (nk > 1)continue;	

			// 다음 격자까지 거리는 현재 위치까지 최단거리 + 1
			int nd = dp[a][b][c] + 1;

			if (nd < dp[nx][ny][nk]) {	// 기존 최단거리보다 작으면
				dp[nx][ny][nk] = nd;	// 업데이트 하고
				q.push({ nx, ny, nk });	// 큐에 push해서 bfs 한번 더

				// 새로 업데이트 된 노드이기 때문에 전에 탐색했더라도
				// 주위 격자에서 더 짧은 최단거리가 나올 가능성이 있음
			}
		}
	}
}

int main(void) {
	scanf("%d %d", &n, &m);

	for (int i = 0; i < n; i++) {
		scanf("%s", adj[i]);

		// 모든 dp배열 값을 정수형 최대값으로 초기화해준다
		for (int j = 0; j < m; j++) {
			for (int l = 0; l < 2; l++) {
				dp[i][j][l] = 0x7fffffff;
			}
		}
	}

	bfs();	// bfs를 통해 dp배열 만들기 시작

	int res = 0x7fffffff;
	// res는 벽을 안부시고 도착한 최단거리와
	// 벽을 부시고 도착한 최단거리 중 작은 값이다
	for (int i = 0; i < 2; i++) {
		res = min(res, dp[n - 1][m - 1][i]);
	}

	if (res == 0x7fffffff) {	// 만약 그 값이 초기 설정값이면
		printf("-1\n");	 // 벽을 부셔도 도달할 수 없다
	}
	else {	// 도달할 수 있으면 최단경로 출력
		printf("%d\n", res);
	}

	return 0;
}

'알고리즘 > PS' 카테고리의 다른 글

[백준 14997] 주난의 난  (0) 2020.08.20
[백준 7576] 토마토  (0) 2020.08.20
[백준 2606] 바이러스  (0) 2020.08.20
[백준 4963] 섬의 개수  (0) 2020.08.20
[백준 2178] 미로 탐색  (0) 2020.08.20