본문 바로가기
PS

[BAEKJOON] 2206 벽 부수고 이동하기 (C++)

by bin1225 2023. 7. 7.

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

 

2206번: 벽 부수고 이동하기

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

www.acmicpc.net

 

하루종일 삽질을 했다. 진짜 질문하기 테스트케이스 다 해봤는데, 안됐는데...

초기 거리값들을 100000에서 1000000으로 수정해주니까 통과했다. 1000* 1000이 백만이라는 걸 방금 이 문장을 쓰면서 깨달았다...... 구몬 등록하러 가야하나

 

 

문제

탐색 문제지만 특이한 조건이 포함돼있다. 벽이 존재하는 곳은 갈 수 없지만, 단 한 번 벽을 부수고 이동할 수 있다.

(1,1)지점에서 (N,M)지점까지 이동하는 최단거리를 구하는 문제

 

접근

탐색과정에서 벽을 부쉈는지 여부를 같이 전달한다.

Case는 다음과 같이 3가지 존재한다.

1. 벽을 이미 부수고 온 경우 -> 벽이 없는 곳으로만 이동한다.

2. 벽을 부수지 않은 경우 

2-1. 벽이 있는 곳 -> 벽을 부쉈는지 여부(check)를 true로 업데이트 하고 해당 위치를 방문한다.

2-2. 벽이 없는 곳 -> check를 업데이트 하지 않고 해당 위치를 방문한다.

 

풀이

처음에 dfs로 풀이를 했는데, 시간초과가 발생했다.

dfs로도 조건을 잘 설정하면 풀 수 있는 것 같긴 한데, 일단 최단거리는 그냥 기계적으로 bfs하는 게 맞는 것 같기도 하다.

 

기본적인 bfs를 진행하되, 벽을 부쉈는지 여부 check를 같이 확인한다.

따라서 bfs진행과정에서 사용하는 queue의 형식을 pair<pair<int,int>,int>로 하여 좌표값과 check에 해당하는 값을 전달한다.

탐색을 하며 다음 방문할 위치가 벽인경우와 벽이 아닌 경우로 나누어 탐색한다.

1. 벽인 경우

이미 벽을 부순 경우는 방문할 수 없다.

벽을 부수지 않은 경우 check값을 업데이트 하고 방문 필요 여부를 확인한다.(이미 더 적은 거리값으로 방문한 경우는 방문할 필요가 없다.)

2. 벽이 아닌 경우

check 값을 그대로 전달하며 방문 필요여부를 확인한다.

 

거리값을 기록하는 배열 Visited도 3차원배열로 선언하여 각각의 좌표마다 벽을 부수고 온 경우와 벽을 부수지 않고 온 경우를 모두 기록하였다.

 

또 입력을 string으로 받지 않아서 삽질을 했었는데... 입력이 서로 붙어있는지 확인하고 입력받는 형식을 적절히 작성할 필요가 있다.

 

코드

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#define endl "\n"

using namespace std;

int N, M, ans;
int MAP[1001][1001];
int Visited[1001][1001][2];
int dx[] = { -1,0,1,0 };
int dy[] = { 0,1,0,-1};
queue<pair<pair<int, int>,int>> Q;
void Input() {
	cin >> N>>M;
	string s;
	for (int i = 1; i <= N; i++) {
		cin >> s;
		for (int j = 0; j < M; j++) {
			MAP[i][j+1] = s[j] - '0';
			Visited[i][j+1][0] = 1000000;
			Visited[i][j+1][1] = 1000000;
		}
	}
}

void Solve() {
	int x, y, xx, yy, check;
	Visited[1][1][0] = 1;
	Q.push({ {1,1},0 });
	while (!Q.empty()) {
		x = Q.front().first.second; y = Q.front().first.first; check = Q.front().second;
		Q.pop();

		for (int i = 0; i < 4; i++) {
			xx = x + dx[i]; yy = y + dy[i]; 

			if (xx<1 || xx>M || yy<1 || yy>N) continue;

			if (MAP[yy][xx] == 1) {
				if (check == 1) continue;
				if (Visited[yy][xx][1] > Visited[y][x][check] + 1) {
					Visited[yy][xx][1] = Visited[y][x][check] + 1;
					Q.push({ {yy,xx}, 1});
				}
			}
			if (MAP[yy][xx] == 0) {
				if (Visited[yy][xx][check] > Visited[y][x][check] + 1) {
					Visited[yy][xx][check] = Visited[y][x][check] + 1;
					Q.push({ {yy,xx}, check });
				}
			}
		}
	}
	ans = min(Visited[N][M][0], Visited[N][M][1]);

	if (ans == 1000000) cout << -1<<endl;
	else cout << ans << endl;
}


int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	freopen("input.txt", "r", stdin);
	Input();
	Solve();


	return 0;
}

'PS' 카테고리의 다른 글

[BAEKJOON] 1918 후위 표기식 (C++)  (0) 2023.07.10
[BAEKJOON] 20444 색종이와 가위 (C++)  (0) 2023.07.08
[BAEKJOON] 13164 행복 유치원 (C++)  (0) 2023.06.30
[BAEKJOON] 1092 배 (C++)  (0) 2023.06.29
[BAEKJOON] 15686 치킨 배달 (C++)  (0) 2023.06.26