1번에서 n번으로 이동할건데 처음에는 1칸만 점프할 수 있다
그 이후에는 이전에 x칸 점프했으면 이번에는 x-1,x,x+1칸 중 하나를 선택하여 점프할 수 있다
물론 1칸 이상 점프해야한다
그리고 어떤 돌에는 점프할 수 없다
이때 필요한 최소 점프 횟수는?
--------------------------------------------------------------------------------------------------------------------------------
dp[i][j]를 i칸에 왔을때 점프한 칸의 수가 j칸일때 최소 점프 횟수라고 정의해야할텐데
문제가 n이 최대 10000인데 점프할 수 있는 칸 수 j도 10000으로 잡으면 메모리 초과당할 것 같다
그래도 다행인건 생각해보면 x칸 점프했으면 이후에는 x-1,x,x+1칸 중 하나를 점프해야하므로
가장 많이 점프할 수 있는 칸 수는 얼마일까
x = 1부터 시작해서 1,2,3,...으로 1칸씩 늘려가며 점프할 수 있으니까
1+2+3.... +m<= 10000인 m을 찾으면 된다
m = 140이면 9870
그래서 dp[10000][140]정도를 잡으면 된다
10^6정도니까 메모리는 적당
이렇게 하면 이제 1번부터 시작하는데 2번 돌에 갈 수 있으면 dp[2][1] = 1
그 다음 i = 2,3,...,n에 대하여
x = 1,2,..,140에 대해 x-1칸 뛰는 경우 dp[i+x-1][x-1] = dp[i][x] + 1
x칸 뛰는 경우 dp[i+x][x] = dp[i][x] + 1
x+1칸 뛰는 경우 dp[i+x+1][x+1] = dp[i][x] + 1
당연히 중요한 점은 i+x+1, i+x, i+x-1 <= n이어야하고, A[i+x+1], A[i+x-1], A[i+x]가 각각 갈 수 있는 곳이어야한다
그 다음 정답은 어떻게 찾지?
n번째 칸을 1칸,2칸,,...,140칸 점프해서 이동한 거 모두 유효하므로 dp[n][1],...dp[n][140]중 최솟값
당연하지만 x에 따라 불가능한 경우가 있을 수도 있음
from sys import stdin
n,m = map(int,stdin.readline().split())
A = [0]*(n+1)
for _ in range(m):
m = int(stdin.readline())
A[m] = 1
dp = [[0]*145 for _ in range(n+1)]
if A[2] == 1:
dp[2][1] = 0
else:
dp[2][1] = 1
for i in range(2,n+1):
for x in range(1,143):
if dp[i][x] > 0:
if i+x <= n and A[i+x] == 0:
dp[i+x][x] = dp[i][x] + 1
if i+x-1 <= n and A[i+x-1] == 0:
dp[i+x-1][x-1] = dp[i][x] + 1
if i+x+1 <= n and A[i+x+1] == 0:
dp[i+x+1][x+1] = dp[i][x] + 1
INF = 10**18
answer = INF
for i in range(143):
if dp[n][i] > 0:
if answer > dp[n][i]:
answer = dp[n][i]
if answer == INF:
answer = -1
print(answer)
'알고리즘 > 다이나믹 프로그래밍' 카테고리의 다른 글
스위치를 누른 효과가 j초 남아있는 지속시간 다이나믹 프로그래밍 (0) | 2025.04.07 |
---|---|
양팔저울을 이용해서 무게를 알아낼 수 있는 추를 찾는 방법 (0) | 2025.04.04 |
배열을 뒤집어서 다른 배열과 대응하는 원소끼리 곱의 합의 특징 (0) | 2025.04.03 |
연속하는 구간을 한번 뒤집어야할때 켜져있는 원소들의 합의 최댓값을 구하는 놀라운 방법 (0) | 2025.03.24 |
한번 쉬면 끝까지 쉬어야할 때 최대한 멀리 달리는 다이나믹 프로그래밍 (0) | 2025.03.19 |