코딩테스트/SWEA

[Python, 파이썬] SWEA 1249. [S/W 문제해결 응용] 4일차 - 보급로

알코딩 2024. 10. 16. 02:53

 

출발지(S) 에서 도착지(G)까지 가기 위한 경로 중에
복구 시간이 가장 짧은 경로에 대한 총 복구 시간을 구하는 문제.

 

 

1. DFS

def DFS(i, j, costs):
 
    global min_costs
 
    if not (0 <= i < N and 0 <= j < N): # 0<= x <N 사이에 있지 않을때
        return
 
    if cost_map[i][j] <= costs: # 더 저렴한 경로가 있을 때
        return
 
    if cost_map[N-1][N-1] <= costs: # 현재 탐색 중인 경로가 이전 경로보다 cost가 클 시
        return # 더 탐색하지 않고 종료
 
    cost_map[i][j] = costs # 메모이제이션
 
    DFS(i+1, j, costs+A[i][j]) # 아래로 이동
    DFS(i, j+1, costs+A[i][j]) # 오른쪽으로 이동
    DFS(i, j-1, costs+A[i][j]) # 왼쪽으로 이동
    DFS(i-1, j, costs+A[i][j]) # 위로 이동
     
T = int(input()) # 테스트케이스 수 T
 
for test_case in range(1, T+1):
 
    N = int(input()) # 정수 N
    A = [] # 수열 A
 
    # 수열 입력받기
    for i in range(N):
        A.append(list(map(int, input().strip())))
     
    # 탐색 시작
    cost_map = [[10**10] * N for _ in range(N)] # 메모이제이션
    DFS(0, 0, 0) # 가장 짧은 경로 계산
             
    print("#%d %d" %(test_case, cost_map[N-1][N-1])) 
 

메모이제이션+완전 탐색을 위해 풀 수 있는 문제다.

상하좌우를 봐서 N x N 범위 안에 점점 이동하는데, 이때 현재 탐색 중인 경로가 현재 구한 경로보다 비쌀 시 DFS를 종료한다. 또, 현재 위치에 이전에 더 저렴한 경로를 찾았을 시 그 경로를 update한다.

 

if cost_map[i][j] <= costs: # 더 저렴한 경로가 있을 때
        return

if cost_map[N-1][N-1] <= costs: # 현재 탐색 중인 경로가 이전 경로보다 cost가 클 시
    return # 더 탐색하지 않고 종료
 
 

그러나 DFS를 사용하면 한쪽길로 쭉 가기 때문에 시간이 많이 걸린다.

그래서 Recurison 오류와, 시간초과가 발생할 가능성이 높다.

 

 

 

2. BFS

from collections import deque
 
def BFS(i, j):
 
    q = deque()
    q.append((i, j))
    cost_map[i][j] = 0
 
    dx = [0,1,-1,0]
    dy = [1,0,0,-1]
 
    while q:
 
        x, y = q.popleft()
 
        for i in range(4):
 
            nx = x+dx[i]
            ny = y+dy[i]
             
            if (0 > nx or 0 > ny) or (nx >= N or ny >= N): # 범위를 벗어날 시
                continue
 
            if cost_map[x][y]+A[nx][ny] < cost_map[nx][ny]: # cost_map UPDATE
                    cost_map[nx][ny] = cost_map[x][y]+A[nx][ny]
                    q.append((nx,ny))
     
 
T = int(input()) # 테스트케이스 수 T
 
for test_case in range(1, T+1):
 
    N = int(input()) # 정수 N
    A = [] # 수열 A
 
    # 수열 입력받기
    for i in range(N):
        A.append(list(map(int, input())))
     
    # 탐색 시작
    INF = 10**10
    cost_map = [[INF] * N for _ in range(N)] # 메모이제이션
    BFS(0, 0) # 가장 짧은 경로 계산
             
    print("#%d %d" %(test_case, cost_map[N-1][N-1])) 
 

이거 또한 메모이제이션+완전 탐색으로 푸는 방식이다.

DFS를 BFS로 바꾼 거 뿐인데, 시간이 훨씬 적게 걸린다.

 

DFS는 5,247ms가 걸렸지만 BFS는 221ms밖에 안걸렸다!

사실 왜인지는 모르겠는데 BFS가 인접부분부터 찾는 게 DFS보다 더 빨리 최소의 값을 탐색해서 그런거 같다.