새소식

반응형
코딩 테스트

[프로그래머스] 미로 탈출 명령어

  • -
728x90
반응형

문제

  • $n \times m$ 미로가 있다. (x, y) -> (r, c) 로 탈출하는 경로 리턴하기
    • 2 <= n, m <= 50
    • (x, y) ≠ (r, c)
  • l 왼쪽, r 오른쪽, u 위쪽, d 아래쪽 으로 이동할 수 있다.
  • 이동 거리가 총 k여야 하고, 중복 방문해도 된다.
    • 1 <= k <= 2500
  • 경로를 문자열로 표현했을 때 사전 순으로 가장 빠른 경로로 탈출해야 한다.
  • 미로 탈출할 수 없는 경우 "impossible" 리턴

 

풀이 1

  • 사전 순으로 제일 빠른 경로 하나만 탐색하면 되니까 DFS 사용
  • 전체 경로를 탐색하면 $O(4^{2500})$ 으로 시간 초과 나니까 정답 찾으면 멈춰야 한다.
    • answer 를 찾으면 멈춰주기로 함
테스트 케이스 4~8번 제외하고 시간 초과
import sys
sys.setrecursionlimit(10**4)
def solution(n, m, x, y, r, c, k):
    
    dx = (1, 0, 0, -1)  # dlru 순서
    dy = (0, -1, 1, 0)
    ds = ('d', 'l', 'r', 'u')    
    answer = []
    
    def dfs(x, y, string, move):
        if move == k :				# k번 움직였고
            if x == r and y == c:	# 도착한 경우
                answer.append(string)
                return True
            else :					# 도착 못한 경우
                return False
        
        # d, l, r, u 순으로 탐색
        for i in range(4):
            nx, ny = x+dx[i], y+dy[i]
            
            if 0 < nx <= n and 0 < ny <= m and not answer:
                if dfs(nx, ny, string[:]+ds[i], move+1) :
                    break
                    
    dfs(x, y, "", 0)
    if answer:
        return answer[0]
    else:
        return "impossible"

 

 

풀이 2

  • impossible 조건 추가
    • 최소 이동 횟수 : abs(도착지 x 좌표 - 현재 x 좌표) + abs(도착지 y 좌표 - 현재 y 좌표)
    • 최소 이동 횟수가 k보다 많거나,
    • 최소 이동 횟수 제외한 이동 횟수홀수인 경우에는 도착지에 도착 불가능
  • 종료 조건 추가
    • 남은 이동 횟수 안에 도착지까지 갈 수 없는 경우 탐색 멈추기
통과!
import sys
sys.setrecursionlimit(10**4)

dx = (1, 0, 0, -1)  # dlru 순서
dy = (0, -1, 1, 0)
ds = ('d', 'l', 'r', 'u')    
answer = ''

def dfs(x, y, string, move, n, m, r, c, k):
        global answer
        # 남은 횟수 안에 도착지까지 갈 수 없는 경우 stop
        if k < move + abs(x - r) + abs(y - c):
            return
            
        # 정답을 찾은 경우
        if move == k and x == r and y == c:
            answer = string
            return 
        
        # 사전 순으로 탐색
        for i in range(4):
            nx, ny = x+dx[i], y+dy[i]
            
            if 0 < nx <= n and 0 < ny <= m and not answer:
                dfs(nx, ny, string[:]+ds[i], move+1, n, m, r, c, k)
                
def solution(n, m, x, y, r, c, k):
    
    min_move = abs(r-x)+abs(c-y)	# 도착지까지의 최소 이동 횟수
    # 최소 이동 횟수가 k보다 많거나,
    # 최소 이동 횟수 제외한 이동 횟수가 홀 수인 경우에는 도착지에 도착 불가능
    if min_move > k or (k - min_move) % 2 == 1:
        return "impossible"
    
    dfs(x, y, "", 0, n, m, r, c, k)
    return answer

 

풀이 3

  • 위와 동일한 코드인데 재귀가 아닌 반복문을 이용한 DFS
  • 반복문이라 더 빠를 것으로 예상했는데 의외로 더 느렸다.
    • 이 코드는 평균 8ms 인데, 재귀 이용한 코드는 평균 6ms
통과!
from collections import deque

def solution(n, m, x, y, r, c, k):
    dx = (-1, 0, 0, 1)  # urld 순서
    dy = (0, 1, -1, 0)
    ds = ('u', 'r', 'l', 'd')    
    answer = ""
    
    total_move = abs(r-x)+abs(c-y)
    if total_move > k or (k - total_move) % 2 == 1:
        return "impossible"
    
    q = deque([(x, y, "", 0)])

    while q:
        x, y, string, move = q.pop()
        
        if move == k and x == r and y == c :
            return string
        
        for i in range(4):
            nx, ny = x+dx[i], y+dy[i]
            
            if 0 < nx <= n and 0 < ny <= m and k >= move + abs(r-x) + abs(c-y) :
                q.append((nx, ny, string+ds[i], move+1))

    return answer

 

 

풀이 4

  • BFS로 풀 수는 없을까..?
  • 시간 초과 나는데, visited 추가하면 통과 된다. (근데 느림)
  • 시간 초과를 해결 못해서 다른 분 코드를 참고했는데 visited가 어떤 면에서 경우의 수를 차단해주는지 모르겠다. 탐구 필요!
from collections import deque

def solution(n, m, x, y, r, c, k):
    dx = (1, 0, 0, -1)  # dlru 순서
    dy = (0, -1, 1, 0)
    ds = ('d', 'l', 'r', 'u')    
    answer = ""
    
    total_move = abs(r-x)+abs(c-y)
    if total_move > k or (k - total_move) % 2 == 1:
        return "impossible"
    
    q = deque([(x, y, "", 0)])
    # visited[x][y][k] : x, y 에서 k번째 움직였을 때 문자열
    visited = [[[False]*(k+1) for _ in range(m+1)] for _ in range(n+1)]
    visited[x][y][0] = True
    while q:
        x, y, string, move = q.popleft()
        
        if move == k and x == r and y == c :
            return string
        
        for i in range(4):
            nx, ny = x+dx[i], y+dy[i]
            
            if 0 < nx <= n and 0 < ny <= m and k >= move + abs(r-x) + abs(c-y) and not visited[nx][ny][move+1]:
                visited[nx][ny][move+1] = True
                q.append((nx, ny, string+ds[i], move+1))

    return answer

 

 

 

References

  • 프로그래머스 Lv3
반응형

'코딩 테스트' 카테고리의 다른 글

[프로그래머스] 타겟 넘버  (0) 2023.05.12
[백준] 2503 숫자 야구  (0) 2023.05.12
[백준] 20002 사과나무  (0) 2023.05.05
[백준] 3273 두 수의 합  (0) 2023.05.05
[프로그래머스] 주식가격  (0) 2023.05.04
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.