준규는 N×M 크기의 미로에 갇혀있다. 미로는 1×1크기의 방으로 나누어져 있고, 각 방에는 사탕이 놓여져 있다. 미로의 가장 왼쪽 윗 방은 (1, 1)이고, 가장 오른쪽 아랫 방은 (N, M)이다.
준규는 현재 (1, 1)에 있고, (N, M)으로 이동하려고 한다. 준규가 (r, c)에 있으면, (r+1, c), (r, c+1), (r+1, c+1)로 이동할 수 있고, 각 방을 방문할 때마다 방에 놓여져있는 사탕을 모두 가져갈 수 있다. 또, 미로 밖으로 나갈 수는 없다.
준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수의 최댓값을 구하시오.
첫째 줄에 미로의 크기 N, M이 주어진다. (1 ≤ N, M ≤ 1,000)
둘째 줄부터 N개 줄에는 총 M개의 숫자가 주어지며, r번째 줄의 c번째 수는 (r, c)에 놓여져 있는 사탕의 개수이다. 사탕의 개수는 0보다 크거나 같고, 100보다 작거나 같다.
첫째 줄에 준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수를 출력한다.
3 4
1 2 3 4
0 0 0 5
9 8 7 6
31
사탕 개수가 최대가 되도록 해야 한다. 이때, 현재 위치에서 이동이 오른쪽, 아래, 대각선으로밖에 안된다. 그렇게 되면 "현재위치에서 오른쪽, 아래, 대각선 중 최댓값으로 이동"이라는 행위를 반복하게 된다. 그리고 이전 경로 중 최댓값에서 그 다음 위치로 가게 되면 각 위치에서의 사탕 개수의 최댓값을 구할 수 있다. 따라서 이는 DP로 풀이가 가능하다. 전형적인 DP문제가 된다.
n,m = map(int, input().split())
miro = []
for i in range(n) :
line = list(map(int, input().split()))
miro.append(line)
dp = [ [-1]*m for _ in range(n)]
dp[0][0] = miro[0][0]
for j in range(n) :
for k in range(m) :
if j == 0 and k == 0 :
continue
if j == 0 and k >= 1 :
dp[j][k] = dp[j][k-1] + miro[j][k]
continue
elif k == 0 and j >= 1 :
dp[j][k] = dp[j-1][k] + miro[j][k]
else :
dp[j][k] = max(dp[j-1][k], dp[j][k-1],dp[j-1][k-1]) + miro[j][k] ## here
print(dp[n-1][m-1])
위 코드에서 ## here 표시한 부분은 사실 max(dp[j-1][k], dp[j][k-1]) + miro[j][k] 이렇게 고쳐도 된다. 왜냐하면 대각선으로 이동은 돌아가는 경로보다 사탕을 덜 주울 수밖에 없기 때문이다. 이것까지 고려할 수 있었다면 조금이나마 더 간단한 코드를 짤 수 있었겠다.