알고리즘 입문 수업을 듣고 중요한 내용을 정리했습니다.
개인 공부 후 자료를 남기기 위한 목적이므로 내용 상에 오류가 있을 수 있습니다.
문제
[알리바바와 40인의 도둑(동적 계획법)]
알리바바는 40인의 도둑으로부터 금화를 훔쳐 도망치고 있다.
알리바바는 평소에 잘 가지 않던 계곡의 돌다리로 도망가고자 한다.
계곡의 돌다리는 N*N개의 돌로 구성되어 있으며, 각 돌다리들은 높이가 서로 다르다.
해당 돌다리를 건널 때 돌의 높이만큼 에너지가 소비되며, 반드시 최단거리로 이동한다.
즉, 현재지점에서 오른쪽 또는 아래쪽으로만 이동해야 한다.
N*N의 계곡 돌다리 격자정보가 주어지면, (1, 1)에서 (N, N)까지 가는데 드는 에너지의 최소량을 구하는 프로그램을 작성하시오. 만약, 위의 예시처럼 N=3인 돌다리 격자정보가 주어진다면 (1, 1)좌표에서 (3, 3)좌표까지 가는데 드는 최소 에너지는 14이다. (ex. 3+2+3+4+2 = 14)
*입력 설명
첫 번째 줄에는 자연수 N(1 ≤ N ≤ 20)이 주어진다.
두 번째 줄부터 계곡의 N*N 격자의 돌다리 높이정보가 주어진다.
단, 돌다리의 높이는 10보다 작은 자연수이다.
*출력 설명
첫 번째 줄에 (1, 1)출발지에서 (N, N)도착지로 가기 위한 최소에너지를 출력한다.
풀이(Python)
답안(1) : Bottom-Up
import sys
sys.stdin = open('AA/input_79.txt', 'rt')
if __name__ == "__main__":
n = int(input())
arr = [list(map(int, input().split())) for _ in range(n)]
dy = [[0]*n for _ in range(n)]
dy[0][0] = arr[0][0]
for i in range(1, n):
dy[0][i] = dy[0][i-1] + arr[0][i]
dy[i][0] = dy[i-1][0] + arr[i][0]
for i in range(1, n):
for j in range(1, n):
dy[i][j] = min(dy[i-1][j], dy[i][j-1]) + arr[i][j]
print(dy[n-1][n-1])
# 출력 : 25
답안(2) : Top-Down(재귀함수 & 메모이제이션)
import sys
sys.stdin = open('AA/input_79.txt', 'rt')
def DFS(x, y):
if dy[x][y] > 0: # 컷엣지(메모이제이션)
return dy[x][y]
if x == 0 and y == 0:
return arr[0][0]
else:
if y == 0: # 0열에 위치하는 경우
dy[x][y] = DFS(x-1, y) + arr[x][y]
elif x == 0: # 0행에 위치하는 경우
dy[x][y] = DFS(x, y-1) + arr[x][y]
else:
dy[x][y] = min(DFS(x-1, y), DFS(x, y-1)) + arr[x][y]
return dy[x][y]
if __name__ == "__main__":
n = int(input())
arr = [list(map(int, input().split())) for _ in range(n)]
dy = [[0]*n for _ in range(n)]
print(DFS(n-1, n-1))
# 출력 : 25
input_79.txt(입력)
5
3 7 2 1 9
5 8 3 9 2
5 3 1 2 3
5 4 3 2 1
1 7 5 2 4
중요내용(Bottom-Up)
- 2차원 리스트 dy에는 해당 지점까지 도착하는데 소비되는 최소에너지값을 저장한다.
- dy[i][j]는 출발지점(dy[0][0])을 포함해서 해당 지점까지 도착하는데 소비되는 최소에너지 크기를 의미한다.
- 2차원 리스트 dy의 0행과 0열은 해당 지점에 도달하는 경로가 1가지 밖에 없으므로 2차원 리스트 dy에 초기값을 미리 설정해두는 것이다.
- 만약, 특정 위치에 도달할 수 있는 경로가 2가지라면 해당 위치까지 도달하는데 소비되는 에너지가 최소인 값을 dy[i][j]에 저장한다.
- 문제의 설명과 달리 위의 코드답안에서는 출발지점이 (0, 0)이고 최종 도착지점이 (N-1, N-1)이다.
- 또한, 2차원 리스트 dy의 0행과 0열 위치는 이미 초기값을 가지고 있기 때문에 실질적인 시작지점은 dy[1][1]이 된다.
중요내용(Top-Down)
- 탑다운 방식에서는 상태트리의 최상단 부모노드가 도착지점인 DFS(N-1, N-1)이다.
- 참고로, x는 2차원 리스트의 행을 의미하고 y는 2차원 리스트이 열을 의미한다.
- 2차원 리스트 dy의 0행과 0열 위치에서는 DFS() 재귀함수의 호출이 반드시 한 방향으로만 이루어져야 한다.
- 즉, 상태트리에서 뻗어나가는 노드가 오직 1개만 존재해야 한다. (해당 위치에 도착하는 경로가 오직 1개이기 때문)
- 동일한 지역을 재귀함수로 호출하는 경우에는 메모이제이션을 통해 더 이상 재귀함수를 호출하지 않고(상태트리에서 노드를 뻗지 않고) 2차원 리스트 dy에 이미 저장된 값을 리턴해줘야 한다.(컷엣지)
- 참고로, 2차원 리스트 dy에는 해당 위치에 도달하는데 소비되는 에너지량을 저장하고 이를 메모이제이션(컷엣지)에 활용한다.
- 만약, 메모이제이션을 하지 않는다면 N의 크기가 클수록 코드실행에 걸리는 시간이 기하급수적으로 늘어날 것이다. (시간복잡도 개선을 위해 메모이제이션 필수)
'알고리즘' 카테고리의 다른 글
Algorithm - 동전교환(냅색 알고리즘) (0) | 2022.02.05 |
---|---|
Algorithm - 가방문제(냅색 알고리즘) (0) | 2022.02.05 |
Algorithm - 가장 높은 탑 쌓기(LIS 응용) (0) | 2022.02.03 |
Algorithm - 최대 선 연결하기(LIS 응용) (0) | 2022.02.03 |
Algorithm - 최대 부분 증가수열(LIS : Longest Increasing Subsequence) (0) | 2022.02.03 |
댓글