알고리즘 문제(SOL)

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

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

 

2206번: 벽 부수고 이동하기

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

www.acmicpc.net

 

BFS/DFS에서 길을 찾아야하는데, 이번에는 벽을 부술 수 있게 되었다.

기존의 BFS/DFS과 다른 유형의 문제이다.

 

SOL)

"벽을 부순다는 개념을 어떻게 구현 해줄까." 가 key point인 문제이다. 

 

idea 1. 진짜, board에 벽을 1 → 0으로 바꿔주고, 다시 탐사를 진행한다. ⇒ 1000*1000 맵이기 때문에, 벽을 다 하나씩 바꾸고 bfs를 돌리면, BFS 시간복잡도 * 벽의 갯수 = NM * NM(최대) => NM^2  미뗫다. 안된다.

 

idea 2. 벽을 부수고(1개) 거리를 기록한 board, 벽을 부수지 않고 거리를 기록한 board 2개를 가지고, 먼저 도착하는 것의 거리를 출력해준다. 왜냐하면, 먼저 도착한다면 , N-1,M-1의 값이 큐에 빨리 추가가 될거기 때문

⇒ 이럴려면, 3차원 배열을 선언해줘서, 각각의 상태를 나타내어 주면 된다.

 

idea 3. DFS+ backtracking을 해준다.

=> backtracking 형식. 벽을 1번 부섰을 때 , dfs 진행. 하지만, 그 방법이 최솟값인지는 확실하지 않으니, 어쨋든 다 돌아 봐야함. 이 방법은 안됨. (NM^2)( 물론 backtracking으로 줄일 수 있겠지만, 줄일 수 있을지 없을지 확실하지 않기 때문에, 난 이걸 선택하지 않겠음)

 

제일 만만해 보이는 idea 2를 선택하겠음.

일단, BFS를 이용했으므로, 최단거리는 걱정없고,  벽을 부셨을때, 안부셨을 때, 상태를 메모리 공간을 더 활용해서 기록하는 아이디어 이므로, 코드의 가독성도 좋을거 같음.

import sys
from collections import deque
input = sys.stdin.readline

N,M = map(int,input().split())
board= [list(map(int,input().rstrip())) for _ in range(N)]
visited=[[[0]*M for _ in range(N)] for _ in range(2)]
dq = deque()
# 벽을 부수고 거리를 기록한 board
# 벽을 부수지 않고 거리를 기록한 board를 3차원의 형태로 나타내어준다.
dx=(1,0,-1,0)
dy=(0,1,0,-1)

def moving(wall,y,x):
    visited[wall][y][x] = 1
    dq.append((wall,y,x))
    while dq:
        wall,y,x = dq.popleft()
        if y== N-1 and x == M-1 :
            return visited[wall][y][x] # 어차피, 먼저 도착하는 친구가, 큐에 먼저 추가되기 때문에, 순서는 신경쓰지 않아도 된다.
        for k in range(4):
            ny=y+dy[k]
            nx=x+dx[k]
            if (0<=ny<N and 0<=nx<M) and visited[wall][ny][nx] ==0:
                if board[ny][nx] == 0:
                    visited[wall][ny][nx] = visited[wall][y][x] +1
                    dq.append((wall,ny,nx))
                if board[ny][nx] == 1 and wall==0 :
                    visited[1][ny][nx] = visited[wall][y][x] +1
                    dq.append((1,ny,nx))
    return -1

print(moving(0,0,0))