코딩테스트/👩‍💻 이코테

[이코테/다이나믹프로그래밍/DP] 금광(정답,풀이)

병아리는삐약삐약 2023. 10. 19. 14:41

문제

- n x m 크기의 금광의 각 칸은 특정한 크기의 금이 들어 있음
- 채굴자가 첫 번째 열부터 출발해 금을 캠
- 첫 번째 열의 어느 행에서든 출발할 수 있고, 이후 m번에 걸쳐 매번 오른쪽위/오른쪽/오른쪽 아래로의 이동을 수행
- 채굴이 끝난 후 채굴자가 얻을 수 있는 금의 최대 크기 출력

정답

for tc in range(int(input())):
    n,m = map(int,input().split())
    array = list(map(int,input().split()))

    dp =[]
    index = 0
    for i in range(n):
        dp.append(array[index:index+m])
        index+=m
    
    # dp[i][j] 칸 = 왼쪽 위/왼쪽/왼쪽 아래 세 개의 값 중 가장 큰 값. 
    for j in range(1,m):
        for i in range(n):
            if i == 0: # 맨 윗줄 -> 왼쪽 위는 들어올 수 없음
                left_up=0
            else:
                left_up=dp[i-1][j-1]
            if i == n-1: # 제일 아랫줄 -> 왼쪽 아래에서는 들어올 수 없음
                left_down = 0
            else:
                left_down = dp[i+1][j-1]

            left = dp[i][j-1]
            dp[i][j] = dp[i][j] + max(left_up,left_down,left)
    
    result = 0
    for i in range(n):
        result = max(result, dp[i][m-1])

    print(result)

 

풀이

아무래도 DP문제인걸 알고 접근하니 푸는 아이디어는 금방 생각했다.

이전의 값+내 값을 더했을 때 가장 큰 값을 계속해서 선택해 나가는거였는데,

 

처음에 나는 첫 열부터 시작해서 둘째 열, 셋째 열 ... 마지막 열까지 세로로 반복문을 돌려야 된다고 생각했고

내 값 + 다음 이동 후의 값을 다음 칸에 저장시키고, 내 밑의 열에서도 밑의 열 + 다음 이동 후 값을 다음 칸에 저장

(이 때 이전에 가지고 있던 값과 비교해 큰 값 저장)시키는 로직을 생각했는데, 

 

답지에서는 array[I][j]가 있을 때, 그 값은 왼쪽 상단/ 왼쪽/ 왼쪽 하단 세 군데에서 들어올 수 있으니

내 값 + 들어올 수 있는 가장 큰 값을 계속해서 더해나가는 로직을 구현했다.

 

아래는 도출된 점화식.

dp[i][j] = dp[i][j] + max(dp[i-1][j-1],dp[i][j-1],dp[i+1][j-1])

이 때, 열의 인덱스가 0이면 왼쪽 상단에서는 들어올 수 없으므로 0 으로 초기화, 

마찬가지로 열의 인덱스가 n-1이면 왼쪽 하단에서는 들어올 수 없으므로 0으로 초기화한다.

 

모든 로직을 반복한다면 테이블에는 각 칸을 거칠 때 가장 금을 많이 캘 수 있는 금의 크기가 저장되어 있을 것임.

그리고 제일 끝 dp[i][-1] 의 값들 중 가장 큰 값을 출력하면 된다.!!!

 

 

 

역시 DP에서는 점화식을 떠올리는게 중요하다는 생각을 했다!

 

 

 

참고

이것이 취업을 위한 코딩테스트다(with.python)