본문 바로가기
파이썬/코딩테스트

[파이썬] 코딩테스트 15 구현_미로탐색 ☆

by nemonemonemo 2025. 8. 7.

문제

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


백준 2178번 - 미로 탐색 문제 풀이 전 문제 이해하기

이 문제는 '미로' 위를 출발점에서 도착점까지 최단거리로 이동하는 문제이다.

이동은 오른쪽, 왼쪽, 위, 아래 4가지 방향만 가능하며, 벽은 지나갈 수 없다.

즉, 최단거리 탐색 문제 = BFS 방식으로 풀어야 한다.


문제를 쉽게 이해하기 위한 준비

1. 아이디어 요약

  • 큐 방식(BFS) 을 활용해 이동할 수 있는 경로를 탐색한다.
  • 좌표 기준으로 큐에 넣는다.
    • 예: [(x, y)] 형태 → 한 칸씩 이동
  • 지도에서의 거리 기록은 graph 자체에 표시한다.
    • 별도의 distance 리스트 없이, graph를 갱신하면서 거리 기록
  • 시작점은 좌측 상단 (0,0)

BFS의 흐름 정리

  • 출발 지점 : now = (0, 0)
  • 큐에 시작점을 넣고 출발 : q = [(0, 0)]
  • 이동 가능한 방향 : 왼(L), 오(R), 위(U), 아래(D) → 총 4방향
  • 갈 수 없는 경우는 다음과 같다.
    • 지도 바깥으로 나간 경우
    • 벽인 경우 (0인 경우)
  • 갈 수 있는 경우:
    • 큐에 해당 위치 추가
    • 그 위치의 값을 현재 위치 + 1로 갱신 → 거리 증가

앞에서 풀었던 "특정 거리 도시 찾기" 문제와의 비교

구분 특정 거리 도시 찾기 미로 탐색
지도 형태 노드 & 간선 (연결리스트) 평면 격자 (2차원 리스트)
인접 정의 연결된 도로 (정해진 노드) 상하좌우 4방향 직접 계산
거리 기록 별도의 distance 리스트 graph 자체에 거리 기록
사용 알고리즘 BFS BFS (반드시 BFS!)

입력 처리 단계별 설명

이제 본격적으로 입력을 어떻게 처리하는지 한 줄씩 설명한다.

(1) 지도 크기 입력받기

n, m = map(int, input("가로 세로 크기 입력: ").split())
  • input() 함수로 사용자에게 지도의 크기를 입력받는다. 예: "4 6"
  • "4 6" → .split()을 통해 공백 기준으로 "4", "6" 나눠진다.
  • map(int, …)를 통해 문자열을 정수로 바꾼다 → [4, 6]
  • n, m에 각각 할당되므로 n = 4, m = 6이 된다.

(2) 지도를 한 줄씩 받아서 2차원 리스트로 만들기

graph = []
for i in range(n):
    t = input("지도에 대한 {0}번째 가로줄: ".format(i+1))
    t = list(map(int, [i for i in t]))
    graph.append(t)

●  첫 줄

graph = []
  • graph는 전체 지도를 저장할 리스트이다.
  • 지도를 한 줄씩 받아서 2차원으로 구성할 예정이므로 빈 리스트로 시작한다.

● for문

for i in range(n):
  • 총 n줄(세로 길이만큼)의 지도를 입력받아야 하므로 n번 반복한다.
  • 각 줄마다 가로 방향의 정보가 입력된다.

● 사용자로부터 지도 한 줄 입력 받기

t = input("지도에 대한 {0}번째 가로줄: ".format(i+1))
  • 현재 몇 번째 줄인지 사용자에게 안내하며 입력을 받는다.
  • 예: 101111 같은 문자열이 들어온다.

● 문자열을 숫자의 리스트로 변환

t = list(map(int, [i for i in t]))
  • 입력받은 문자열 "101111"을 리스트 컴프리헨션으로 한 글자씩 분리 → ['1','0','1','1','1','1']
  • map(int, …)를 이용해 문자열을 정수로 바꾼다 → [1, 0, 1, 1, 1, 1]
  • list()로 감싸서 다시 리스트 형태로 변환한다.
더보기
더보기

원래 코드

t = list(map(int, [i for i in t])) 
  • t가 문자열이라면(예: "10111")
  • [i for i in t] → 문자열의 각 문자를 리스트로 변환 → ['1','0','1','1','1']
  • map(int, ...) → 리스트의 각 문자열 요소를 정수로 변환 → [1,0,1,1,1]
  • list(...) → map 객체를 리스트로 만들어 최종 결과 [1,0,1,1,1]

for문으로 푼 버전

# 예: 사용자가 "10111" 입력
t_str = input().strip()  # t_str = "10111"

t_list = []  # 변환된 숫자를 담을 빈 리스트 생성

for ch in t_str:         # 문자열의 각 문자 ch를 하나씩 꺼냄
    num = int(ch)         # 문자 ch를 정수로 변환
    t_list.append(num)    # 변환한 숫자를 리스트에 추가

t = t_list                # 이제 t는 [1,0,1,1,1] 

동작 과정 예시

사용자가 "10111" 입력 → t_str = "10111"

  1. 첫 번째 반복
    • ch = '1'
    • num = int('1') → 1
    • t_list.append(1) → t_list = [1]
  2. 두 번째 반복
    • ch = '0'
    • num = int('0') → 0
    • t_list = [1, 0]
  3. 세 번째 반복
    • ch = '1' → 1
    • t_list = [1, 0, 1]
  4. 네 번째 반복
    • ch = '1' → 1
    • t_list = [1, 0, 1, 1]
  5. 다섯 번째 반복
    • ch = '1' → 1
    • t_list = [1, 0, 1, 1, 1]

결과

t = [1, 0, 1, 1, 1]
 

이제 t는 문자열이 아니라 숫자로 구성된 리스트가 되어, BFS에서 1(길), 0(벽) 판별을 바로 할 수 있다.

  변환된 리스트를 전체 지도에 추가

graph.append(t)
  • 변환한 리스트 t를 graph에 추가한다.
  • 이 과정을 반복하면 graph는 아래처럼 구성된다 :
[[1, 0, 1, 1, 1, 1],
 [1, 0, 1, 0, 1, 0],
 [1, 0, 1, 0, 1, 1],
 [1, 1, 1, 0, 1, 1]]

정리

  • 지도의 크기는 n x m 으로 입력받는다.
  • 각 줄을 숫자의 리스트로 바꿔서 전체 graph를 구성한다.
  • 이 그래프는 이후 탐색 과정에서도 활용되며, 거리 정보를 직접 갱신하는 데 사용된다.
  • 다음 단계에서는 이 graph를 가지고 BFS를 통해 최단 경로를 구하게 된다.



최종 코드 설명

핵심 아이디어 요약

  • BFS 탐색 사용
    • 무조건 최단거리 → BFS만 가능 (DFS는 부적합)
  • 큐(deque) 활용
    • 앞으로 방문할 좌표들을 넣고 하나씩 꺼내며 탐색
  • 거리 기록은 graph에 직접
    • 따로 distance 배열 없이, 원래 지도에 바로 거리 기록

전체 코드

n,m = map(int, input("가로 세로 크기입력: ").split(" "))
  • 지도의 크기를 입력받는다.
  • input() 함수로 문자열을 입력받고 → split(" ")으로 공백을 기준으로 나눈다
  • "4 6" → ["4", "6"] → map(int, …)로 정수 변환 → n=4, m=6으로 저장

graph = []
for i in range(n):
    t = input("지도에 대한 {0}번째 가로줄: ".format(i+1))
    t = list(map(int, [i for i in t]))
    graph.append(t)
  • graph는 지도를 저장할 2차원 리스트이다
  • 총 n줄만큼 반복하여 한 줄씩 입력받는다

예시:

입력: 101111
→ '1','0','1','1','1','1' → [1,0,1,1,1,1]
  • 이렇게 변환한 리스트를 graph에 한 줄씩 추가하여 전체 지도를 만든다

dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
  • 상하좌우 4방향으로 움직이기 위한 좌표 변화값
  • dx, dy는 각 방향에 따라 x축, y축이 어떻게 변하는지를 의미한다
    • 왼쪽 (L): x+0, y-1
    • 오른쪽 (R): x+0, y+1
    • 위쪽 (U): x-1, y+0
    • 아래쪽 (D): x+1, y+0

from collections import deque
  • deque는 큐(Queue)를 빠르게 처리할 수 있게 해주는 자료구조이다
  • 일반 리스트보다 popleft()가 훨씬 빠르므로 BFS에 적합하다

BFS 함수 구현

def bfs_miro(start):
  • BFS 탐색을 위한 함수 정의이다
  • start는 출발 좌표 (0,0)이 들어온다

    q = deque()
    x_pos, y_pos = start
    q.append((x_pos, y_pos))

  • 큐 q를 초기화한다
  • 시작 위치인 (0,0)을 큐에 넣고, 탐색을 시작한다

    while q:

  • 큐가 빌 때까지 반복한다
  • 즉, 앞으로 방문할 좌표가 없을 때까지 계속 진행한다

        now_x, now_y = q.popleft()

  • 현재 위치를 큐에서 꺼낸다
  • 처음에는 (0,0)이 꺼내지며, 점점 다음 위치들이 추가된다

        for i in range(4):
            next_x = now_x + dx[i]
            next_y = now_y + dy[i]
  • 현재 위치에서 상하좌우로 이동할 수 있는 다음 좌표들을 계산한다

            if 0 <= next_x < n and 0 <= next_y < m:
  • 다음 위치가 지도 바깥으로 나가지 않는지 확인한다
  • 파이썬 리스트 인덱스는 0부터 시작하므로 (0 ≤ x < n, 0 ≤ y < m) 조건 필요

                if graph[next_x][next_y] == 1:
  • 다음 위치가 인지 확인한다 (1인 경우)
  • 벽(0)이거나 이미 방문한 경우(이미 숫자가 바뀐 경우)는 패스한다

                    graph[next_x][next_y] = graph[now_x][now_y] + 1
  • 다음 위치에 거리 값 갱신
  • 현재 위치 값에 +1을 하여 다음 칸까지의 거리 기록
    • 예: 출발점 1 → 다음칸 2 → 그다음 3...

                    q.append((next_x, next_y))
  • 방문 가능한 다음 위치를 큐에 추가하여,
  • 이후에도 해당 위치에서 다시 네 방향 탐색을 하게 한다

BFS 실행

bfs_miro((0, 0))
  • (0,0) 출발점에서 BFS 탐색 시작
  • 도착지점까지 가는 경로를 따라, graph에 거리값이 계속 갱신된다

결과 확인

graph
  • 탐색이 모두 끝난 후 graph를 출력하면,
  • 각 칸에 도달하는 최소 거리가 적혀 있게 된다
  • 도착점 (n-1, m-1)의 값이 바로 최단거리가 된다!

전체 코드 (정리)

python
코드 복사
n, m = map(int, input("가로 세로 크기입력: ").split(" "))

graph = []
for i in range(n):
    t = input("지도에 대한 {0}번째 가로줄: ".format(i+1))
    t = list(map(int, [i for i in t]))
    graph.append(t)

dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]

from collections import deque

def bfs_miro(start):
    q = deque()
    x_pos, y_pos = start
    q.append((x_pos, y_pos))

    while q:
        now_x, now_y = q.popleft()
        for i in range(4):
            next_x = now_x + dx[i]
            next_y = now_y + dy[i]
            if 0 <= next_x < n and 0 <= next_y < m:
                if graph[next_x][next_y] == 1:
                    graph[next_x][next_y] = graph[now_x][now_y] + 1
                    q.append((next_x, next_y))

bfs_miro((0, 0))

print("최단거리:", graph[n-1][m-1])


마무리 정리

  • BFS는 최단 거리 탐색에 최적화된 알고리즘이다
  • deque를 이용하여 큐 방식 탐색을 효율적으로 구현했다
  • 이동 가능한 좌표만 조건 체크하여 큐에 추가하고, 거리 정보를 갱신했다
  • 이 문제에서는 graph에 거리값을 직접 기록하는 방식을 사용해서, 별도의 distance 배열이 필요하지 않았다