문제
https://www.acmicpc.net/problem/2206
걸린 시간
02 : 00 : 21 실패
풀이
C++
#include <bits/stdc++.h>
#define INF 987654321
using namespace std;
int n, m;
int maze[1001][1001];
int visited[1001][1001][2];
int dy[4] = {1, -1, 0, 0};
int dx[4] = {0, 0, -1, 1};
int bfs(){
queue<pair<pair<int, int>, bool>> q;
q.push(make_pair(make_pair(1, 1), false));
visited[1][1][0] = 1;
int depth = 0;
while(!q.empty()){
depth++;
int size = q.size();
for(int i = 0; i < size; i++){
auto tmp = q.front();
auto loc = tmp.first;
int y = loc.first;
int x = loc.second;
q.pop();
// 목표 지점 도착
if(y == n && x == m)
return depth;
// 상하좌우
for(int j = 0; j < 4; j++){
int ny = y+dy[j];
int nx = x+dx[j];
bool bore = tmp.second;
if(1 <= ny && ny <= n && 1 <= nx && nx <= m){
if((!bore || maze[ny][nx] == 0) && !visited[ny][nx][bore]){
if(maze[ny][nx] == 1)
bore = true;
visited[ny][nx][bore] = 1;
q.push(make_pair(make_pair(ny, nx), bore));
}
}
}
}
}
return -1;
}
int main(){
scanf("%d %d", &n, &m);
for(int y = 1; y <= n; y++)
for(int x = 1; x <= m; x++)
scanf("%1d", &maze[y][x]);
printf("%d\n", bfs());
return 0;
}
목적지까지 최단 경로를 찾는 bfs 문제이다. 맵의 크기가 M*N 크기이므로 복잡도는 O(MN). 여기서 하나의 벽을 부수고 지나갈 수 있다는 조건이 추가된다.
제일 먼저 벽의 정보를 따로 저장해두고 하나씩 지워가며 매번 bfs 를 수행하는 고지식한 방법이 있다. 이는 벽의 개수가 0개에서 최대 M*N개가 될 수 있으므로 시간초과가 발생하게 된다.
제한시간안에 문제를 통과하기 위해선 조금 더 똑똑한 방법이 필요하다. 큐에 벽을 뚫었는지를 나타내는 변수를 추가로 두어 벽을 만나면 최대 한번 부수고 지나갈 수 있도록 했다.
하지만 이 방법에는 수많은 반례가 존재했다.
4 4
0000
1110
1111
1110
정답 : 7
출력 : -1
대표적으로 위의 반례에서 (3, 4) 위치의 벽을 뚫고 지나가면 목적지에 도달할 수 있지만 -1 이 출력된다. 디버깅을 통해 찾은 원인은 (2, 3) 위치에서 벽을 뚫고 지나온 좌표가 (1, 4) 위치로부터 온 좌표와 중복되었기 때문이였다.
이에 대한 해결책으로 벽을 뚫은 적이 없는 좌표를 먼저 진행시도록 알고리즘을 설계해 보았지만 또 다른 반례가 존재했다. 이런 식으로는 문제를 해결할 수 없을 것 같아 결국 질문 게시판에서 도움을 구했고 방문 배열을 다르게 사용해보라는 핵심적인 힌트를 얻었다.
기존 방문 배열을 3차원으로 바꾸어 벽을 부수고 진행한 경로와 그렇지 않은 경로를 나누면 중복 문제가 해결된다.
'Baekjoon' 카테고리의 다른 글
Baekjoon 1937번 욕심쟁이 판다 (0) | 2020.09.11 |
---|---|
Baekjoon 1916번 최소비용 구하기 (0) | 2020.09.10 |
Baekjoon 2293번 동전 1 (0) | 2020.09.10 |
Baekjoon 9465번 스티커 (0) | 2020.09.09 |
Baekjoon 11052번 카드 구매하기 (0) | 2020.09.09 |
댓글