문제 보기 · Level 3 · 2023 KAKAO BLIND RECRUITMENT · 정답률 40% · 푼 사람 5,723명 (2026-09-30 기준)1
문제
n×m 격자에서 (x, y)에서 출발해 (r, c)로 탈출한다. 왼쪽 위가 (1, 1)이다. 한 번에 상하좌우로 한 칸씩 움직이고 격자 밖으로는 못 나간다. 정확히 k번 움직여 도착해야 하며, 같은 칸을 여러 번 지나도 된다. 이동을 d(아래), l(왼쪽), r(오른쪽), u(위)로 적은 문자열 중 사전 순으로 가장 앞선 것을 돌려준다. 불가능하면 "impossible"을 돌려준다.
- 2 ≤ n, m ≤ 50
- 1 ≤ k ≤ 2,500
- 출발 칸과 탈출 칸은 다르다
풀이
막히면 한 단계씩 펼친다.
필요한 개념
그리디: 사전 순은 앞 글자부터 정해진다. 그래서 앞자리부터 가장 작은 글자를 고르되, 그 글자를 골라도 끝까지 갈 수 있는지만 확인한다.
1단계 · 작은 예로 손으로 풀기
2×2 격자, (1, 1) → (2, 2), k = 2
가능한 경로는 dr, rd 두 개다. 알파벳 순서는 d < l < r < u이므로 d로 시작하는 dr이 답이다.
3×3 격자, (1, 2) → (3, 3), k = 4라면 불가능하다. 가로 1칸, 세로 2칸이라 최소 3번은 움직여야 한다. 한 걸음 옆으로 갔다 돌아오면 2번이 늘어나니, 걸음 수는 3, 5, 7, …만 된다. 4는 안 된다.
2단계 · 가장 단순한 방법과 그 속도
길이 k인 문자열을 사전 순으로 모두 만들어 보며 처음 맞는 것을 고른다. 경우의 수가 4ᵏ이라, k = 2,500이면 1,500자리가 넘는 수다. 어림없다.
3단계 · 핵심 아이디어
- 갈 수 있는지 판단: 지금 칸에서 탈출 칸까지 가로·세로 칸 수의 합(맨해튼 거리)을 dist, 남은 걸음을 remain이라 하자. dist ≤ remain이고 remain − dist가 짝수면 도착할 수 있다. 남는 걸음은 옆 칸에 갔다 돌아오기로 두 걸음씩 쓴다(격자가 2×2 이상이라 옆 칸은 늘 있다).
- 홀수면 못 가는 까닭: 칸을 (행 + 열)이 짝수인 칸과 홀수인 칸, 두 색으로 칠하면 한 걸음마다 색이 바뀐다. 곧 격자는 이분 그래프다. 그래서 두 칸 사이를 어떤 길로 가든 걸음 수는 dist와 홀짝이 같고, remain − dist가 홀수면 도착할 수 없다.
- 짝수 조건은 처음 한 번만: 한 걸음마다 dist는 1 늘거나 1 줄고 remain은 1 준다. 그래서 remain − dist의 홀짝은 끝까지 그대로다. 처음에 짝수면, 걸음마다 dist ≤ remain만 확인하면 된다.
- 앞자리부터 가장 작은 글자: 걸음마다 d, l, r, u 순으로 보고, 격자 안이고 “그 칸에서 남은 걸음으로 도착할 수 있는” 첫 방향을 고른다. 사전 순은 앞 글자가 작으면 뒤와 상관없이 앞서므로, 이렇게 고른 글자를 되돌릴 일이 없다.
4단계 · 코드 흐름
- dist를 구한다. dist > k거나 k − dist가 홀수면
"impossible". - k번 되풀이한다. 이번 걸음 뒤에 남는 걸음 remain = k − (지금까지 걸음) − 1.
- d, l, r, u 순으로 옮겨 본 칸이 격자 안이고 그 칸의 dist ≤ remain이면, 그리로 옮기고 글자를 붙인다.
- 모은 글자를 이어 돌려준다.
5단계 · 파이썬 코드
MOVES = [("d", 1, 0), ("l", 0, -1), ("r", 0, 1), ("u", -1, 0)] # 사전 순
def solution(n, m, x, y, r, c, k):
dist = abs(x - r) + abs(y - c)
if dist > k or (k - dist) % 2 == 1:
return "impossible"
path = []
for step in range(k):
remain = k - step - 1 # 이번 걸음 뒤에 남는 걸음 수
for ch, dx, dy in MOVES:
nx, ny = x + dx, y + dy
if 1 <= nx <= n and 1 <= ny <= m and abs(nx - r) + abs(ny - c) <= remain:
x, y = nx, ny
path.append(ch)
break # 가장 앞선 글자를 골랐으면 끝
return "".join(path)
- x는 행(위아래), y는 열(좌우)이다. d는 행 번호가 1 늘고, l은 열 번호가 1 준다.
abs(a): a의 절댓값이다.break는 안쪽for만 끝낸다. 바깥for는 다음 걸음으로 넘어간다.
6단계 · 실행 추적
n = 3, m = 4, (2, 3) → (3, 1), k = 5. 처음 dist = 1 + 2 = 3이고 5 − 3 = 2는 짝수라 갈 수 있다.
| 걸음 | 뒤에 남는 걸음 | 해 본 방향 (옮긴 칸의 dist) | 고른 글자 | 위치 |
|---|---|---|---|---|
| 1 | 4 | d (2) | d | (3, 3) |
| 2 | 3 | d (밖), l (1) | l | (3, 2) |
| 3 | 2 | d (밖), l (0) | l | (3, 1) |
| 4 | 1 | d (밖), l (밖), r (1) | r | (3, 2) |
| 5 | 0 | d (밖), l (0) | l | (3, 1) |
답은 dllrl이다. 4번째 걸음에서 이미 도착해 있지만 걸음이 남아, 가장 앞선 글자 중 되돌아올 수 있는 r로 한 칸 나갔다 온다.
7단계 · 복잡도와 흔한 실수
걸음마다 방향 4개를 보니 \(O(k)\), 많아야 1만 번이다.
- 방향 순서를 d, l, r, u(알파벳 순)가 아닌 u, d, l, r(보통 쓰는 순)로 둔다.
- 행·열을 거꾸로 써서 d를 열 방향으로 옮긴다.
- 홀짝 조건을 빼먹어 도착하지 못하는 문자열을 돌려준다.
- 깊이 우선 탐색을 가지치기 없이 돌려 시간 초과가 난다. “dist > remain이면 그 가지를 버린다”는 가지치기를 넣으면, 사전 순으로 도는 탐색이 처음 찾는 경로가 답이고 되돌아갈 일도 없어 이 풀이와 같아진다.
-
프로그래머스 스쿨, “미로 탈출 명령어” (https://school.programmers.co.kr/learn/courses/30/lessons/150365), 2026-09-30 조회. ↩