Algorithm
[프로그래머스][python]미로 탈출 명령어
soduddl1
2023. 8. 23. 10:16
문제
https://school.programmers.co.kr/learn/courses/30/lessons/150365
소스코드
from collections import deque
def solution(n, m, x, y, r, c, k):
answer = 'impossible'
q = deque()
q.append([x,y,0,''])
dx = [1,0,0,-1]
dy = [0,-1,1,0]
dic = {0:'d',1:'l',2:'r',3:'u'}
while q:
xx,yy,cnt,arr = q.popleft()
if cnt > k:
continue
if cnt == k:
if (xx == r and yy == c):
answer = arr
break
for s in range(4):
sx = xx + dx[s]
sy = yy + dy[s]
if sx <= 0 or sx > n or sy <=0 or sy > m:
continue
if abs(sx - r) + abs(sy - c) + cnt + 1 > k:
continue
q.append([sx,sy,cnt+1,arr+dic[s]])
break
return answer
설명
BFS를 사용해서 목적지까지 가는 최단거리의 경로를 표현해야하는 문제이다.
미로를 탈출하는 조건은 아래와 같다.
1. 격자의 바깥으로는 나갈 수 없습니다.
2. (x, y)에서 (r, c)까지 이동하는 거리가 총 k여야 합니다. 이때, (x, y)와 (r, c)격자를 포함해, 같은 격자를 두 번 이상 방문해도 됩니다.
3. 미로에서 탈출한 경로를 문자열로 나타냈을 때, 문자열이 사전 순으로 가장 빠른 경로로 탈출해야 합니다.
2 번 조건에 의해 visited 를 체크하지 않고 최단거리를 찾아야한다고 생각할 수 있다. 그러면 시간초과를 어떤식으로 방지할 수 있을까를 생각해야한다. 아래는 내가 시간초과를 피하기 위해 생각한 방법이다.
- bfs탐색시 queue에 (x,y,cnt) cnt는 그동안 움직인 이동횟수이다. 이동횟수가 k 이상이면 continue 처리해준다.
- 새로운 좌표를 queue에 넣을 때 (이동할 좌표와 목적지의 좌표의 거리) + 현재까지 움직인 cnt + 1 (새로운 이동 좌표로 움직이면 1 추가됨)을 계산했을 때 k가 넘어버리면 탐색하지 않는다. 어짜피 의미없는 움직임 이기 때문이다. 미래의 경우를 미리 계산해서 제거해준다.
3번조건에 의해 경로를 처리해야한다. 아래는 이 조건을 만족하면서 시간초과를 피하기 위해 생각한 방법이다.
- 탐색을 사전순으로 한다. dic에 사전순으로 정의해두었다. 그냥 4개밖에 안되니까 직접 설정한다. 그래서 탐색을 할 때 조건에 맞는 경우가 나오면 q에 넣고 바로 break로 나머지는 하지 않는다. 어짜피 사전순이기 때문에 뒤에 있는 경우를 탐색하는건 조건에 맞지 않는다.
- bfs는 최단거리를 탐색하는 알고리즈이다. 그러기 때문에 조건에 맞는 답이 나오면 바로 return 처리해주면 된다.
후기
if abs(sx - r) + abs(sy - c) + cnt + 1 > k:
continue
미래 경우의 수를 생각해주지 않아서 시간초과가 발생했다. 또 사전순으로 처리하면 바로 break처리해주면 되는데 처리를 안해줘서 시간초과가 났다 😭
230901 복습 기록
from collections import deque
def solution(n, m, x, y, r, c, k):
answer = 'impossible'
dd = ["d","l","r","u"]
dx = [1,0,0,-1]
dy = [0,-1,1,0]
q = deque()
q.append([x,y,0,""])
while q:
x1,y1,cnt,tmp = q.popleft()
if (x1 == r and y1 == c) and cnt == k:
answer = tmp
break
if cnt >= k:
continue
for kk in range(4):
xx = x1 + dx[kk]
yy = y1 + dy[kk]
if 0<xx<=n and 0<yy<=m:
if abs(xx-r) + abs(yy-c) + cnt + 1 <= k:
q.append([xx,yy,cnt+1,tmp+dd[kk]])
break
return answer
방문처리를 하지 않고 시간초과를 예방하는 방법
1. 예상경로 + 움직임 횟수를 사전에 예측한 후 안되면 탐색 후보에 넣지 않는다.
현재 경로에서 목적지 까지 위치 + 지금까지 이동한 경로 + 지금 움직일 1 카운트를 더했는데 K 보다 크면 하나마나임
if abs(xx-r) + abs(yy-c) + cnt + 1 <= k:
2. 탐색 후보가 되면 바로 break 처리를 해준다.
사전순으로 가장 빠른 경로가 답이 된다. 사전순으로 탐색하면서 후보가 나오면 바로 break 해서 다음 항목은 탐색하지 않는다
d ~ 로 시작된 경로는 r ~ 경로보다 무조건 답이 되기 때문
["d","l","r","u"]
break 를 안해서 애를 좀 먹었다 😢