알고리즘💻/DP

BOJ 1757번: 달려달려

호프 2021. 1. 24. 04:38

www.acmicpc.net/problem/1757

 

1757번: 달려달려

어제, 그리고 어제 어제 단체달리기를 두 번이나 하였다. 원장선생님의 이러한 하드 트레이닝으로 월드 학생들의 체력은 거의 박지성 수준이 되었다. 그래서 월드 학생들은 운동장을 도는데 정

www.acmicpc.net

아이디어:

DP를 구성하는 방법을 떠올리는 방식이 어렵다.

조건

 - 1분을 달리면 지침 지수는 1이 올라간다. 1분을 쉬면 지침 지수는 1 내려간다. -> 지침지수가 0일 때 쉬어도 그대로 0이다.

 - 쉬기 시작하면 지침지수가 0이 되기 전에는 다시 달릴 수 없다.

 - 달리기가 끝나면 지침지수는 0이 되어야 한다. -> 마지막 n분째에는 달릴 수 없다.

 

DP[x][y][z] = x초에 y의 지침지수를 가지고 z는 뛰고 있는지 여부를 나타낼 때 달린 겨리의 최댓값 저장

 

- j가 1, 0이 아닐 떄:

dp[i][j][1] = dp[i-1][j-1][1] + D[i] #1,0이 아니므로 dp[i-1][j-1][0]인 경우는 고려하지 않음

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

 

- j가 0일 때 : 쉬어도 지침 지수가 그대로 0

dp[i][j][0] = max(dp[i-1][j+1][0], dp[i-1][j+1][1], dp[i-1][j][[0]) #j가 0이므로 dp[i][j][1]은 불가능

 

- j가 1일 때 : 쉬다가 달리는 것이 가능

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

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

 

최대로 멀리 갈 수 있는 거리를 구해야 하므로, dp[n][0][0]을 출력하면 된다.(지침지수 0이려면 마지막에 쉬어야 하니까)

 

※파이썬에서 3중 배열 선언

dp = [[[0]*2 for _ in range(m+5)] for _ range(n+5)]

 

#파이썬으로 제출하면 메모리 초과 나서 C++로 제출함.
import sys
n, m = map(int, sys.stdin.readline().split())
dp = [[[0]*2 for _ in range(m+5)] for _ in range(n+5)]
D = [0]*(n+1)
for i in range(1,n+1):
    D[i]=int(sys.stdin.readline())

for i in range(1,n+1):
    for j in range(m+1):
        if j != 1:
            if j: #j가 1,0이 아닐때
                dp[i][j][1] = dp[i-1][j-1][1] + D[i]
                dp[i][j][0] = max(dp[i-1][j+1][1], dp[i-1][j+1][0])
            else: #j가 0일때
                dp[i][j][0] = max(dp[i-1][j+1][0], dp[i-1][j+1][1], dp[i-1][j][0])
        else: #j가 1일때
            dp[i][j][1] = max(dp[i-1][j-1][1], dp[i-1][j-1][0]) + D[i]
            dp[i][j][0] = max(dp[i-1][j+1][1], dp[i-1][j+1][0])
            
print(dp[n][0][0])

DP배열 선언 할 때 dp = [[[0]*2 for _ in range(m+1)] for _ range(n+1)] 로 했더니 out of index -> j+1을 계산하는 경우를 생각하지 못해서

그 외에도 인덱스 때문에 자잘한 오류가 있었다. 여러번 다시 풀어봐야 할 유형인 것  같다.