728x90
백준 2342_Dance Dance Revolution
시간 제한 2초, 메모리 제한 128MB
# 조건
- DDR은 아래의 그림과 같은 모양의 발판이 있고, 주어진 스텝에 맞춰 나가는 게임이다.
- 발판은 하나의 중점을 기준으로 위, 아래, 왼쪽, 오른쪽으로 연결되어 있다.
- 편의상 중점을 0, 위를 1, 왼쪽을 2, 아래를 3, 오른쪽을 4라고 정하자.
- 처음에 게이머는 두 발을 중앙에 모으고 있다.(그림에서 0의 위치)
- 그리고 게임이 시작하면, 지시에 따라 왼쪽 또는 오른쪽 발을 움직인다. 하지만 그의 두 발이 동시에 움직이지는 않는다.
- 이 게임에는 이상한 규칙이 더 있다.
- 두 발이 같은 지점에 있는 것이 허락되지 않는 것이다. (물론 게임 시작시에는 예외이다)
- 만약, 한 발이 1의 위치에 있고, 다른 한 발이 3의 위치에 있을 때, 3을 연속으로 눌러야 한다면, 3의 위치에 있는 발로 반복해야 눌러야 한다는 것이다.
- 오랫동안 DDR을 해 온 백승환은 발이 움직이는 위치에 따라서 드는 힘이 다르다는 것을 알게 되었다.
- 만약, 중앙에 있던 발이 다른 지점으로 움직일 때, 2의 힘을 사용하게 된다. 그리고 다른 지점에서 인접한 지점으로 움직일 때는 3의 힘을 사용하게 된다. (예를 들면 왼쪽에서 위나 아래로 이동할 때의 이야기이다.)
- 그리고 반대편으로 움직일때는 4의 힘을 사용하게 된다. (위쪽에서 아래쪽으로, 또는 오른쪽에서 왼쪽으로).
- 만약 같은 지점을 한번 더 누른다면, 그때는 1의 힘을 사용하게 된다.
- 만약 1 → 2 → 2 → 4를 눌러야 한다고 가정해 보자. 당신의 두 발은 처음에 (point 0, point 0)에 위치하여 있을 것이다.
- 그리고 (0, 0) → (0, 1) → (2, 1) → (2, 1) → (2, 4)로 이동하면, 당신은 8의 힘을 사용하게 된다. 다른 방법으로 발을 움직이려고 해도, 당신은 8의 힘보다 더 적게 힘을 사용해서 1 → 2 → 2 → 4를 누를 수는 없을 것이다.
입력
- 입력은 지시 사항으로 이루어진다.
- 각각의 지시 사항은 하나의 수열로 이루어진다.
- 각각의 수열은 1, 2, 3, 4의 숫자들로 이루어지고, 이 숫자들은 각각의 방향을 나타낸다.
- 그리고 0은 수열의 마지막을 의미한다.
- 즉, 입력 파일의 마지막에는 0이 입력된다. 입력되는 수열의 길이는 100,000을 넘지 않는다.
# 접근 방법
- 발의 위치를 0, 1, 2, 3, 4 로 기록해준다.
- 이제 점화식을 세우는 것이 관건인데 왼발과 오른발을 모두 고려하여야하고, 각 발이 마지막으로 누른 위치에 따라 다음 위치를 누를 때 추가되는 점수가 다른 점에서
- 왼발과 오른발 각각이 마지막으로 누른 버튼위치에 따른 점수를 기록하면 된다.
- 그래서 dp테이블은 다음과 같이 구성하였고
- dp[현재 스탭 인덱스][왼발최종위치][오른발최종위치]
- 점화식은 다음과 같이 구성하였다.
- dp[현재 스탭 인덱스][왼발최종위치][오른발최종위치] = dp[직전 스탭 인덱스][왼발최종위치][오른발최종위치] + 이동하여 버튼을 누르는데 든 힘
만약 1을 누를 차례라면
- dp[현재스탭인덱스][1][직전 오른발최종위치]
- dp[현재스탭인덱스][직전 왼발최종위치][1]
이 두가지를 각각 구하여 저장해두면 된다.
- 5번 반복 하는 이유 -> 직전 단계의 모든 경우의 수를 고려하는 것
- 즉, 처음에는 왼발 또는 오른발 2가지 경우의 수 -> 이후 왼발에 대해 2개, 오른발에 대해 2개 총 4개 -> 8개 이렇게 경우의 수가 늘어나는 것을
- 왼발의 모든 위치와 오른발의 모든 위치로 기록해놓는 것
- 따라서, 왼발 오른발이 같은 위치에 존재하는 경우도 생기지만 이 경우 최소가 될 수 없으므로 고려하지 않아도 된다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
INF = float('inf')
def dist(cur, next):
if cur == next:
return 1
elif cur == 0:
return 2
elif abs(cur-next) % 2 == 0:
return 4
else:
return 3
inst = [*map(int, input().split())]
# dp [n번째 움직임][왼발 위치][오른발 위치]
# 0, 1, 2, 3, 4가 있으므로 5의 크기로 생성
dp = [[[INF for _ in range(5)] for _ in range(5)] for _ in range(len(inst) +1)]
dp[0][0][0] = 0
for i in range(1, len(inst)):
move = inst[i-1]
for left in range(5):
for right in range(5):
# 왼발 움직이고 오른발 고정
dp[i][move][right] = min(dp[i][move][right], dp[i-1][left][right] + dist(left, move))
# 오른발 움직이고 왼발 고정
dp[i][left][move] = min(dp[i][left][move], dp[i-1][left][right] + dist(right, move))
result = INF
for i in range(5):
for j in range(5):
result = min(result, dp[len(inst) -1 ][i][j])
print(result)
print(dp)
728x90
'ALGORITHM > DP(동적 계획법)' 카테고리의 다른 글
[백준 27440번] 파이썬 - 1로 만들기 3 (0) | 2023.07.10 |
---|---|
[백준 20303번] 파이썬 - 할로윈의 양아치 (0) | 2023.06.22 |
[백준 14002번] 파이썬 - 가장 긴 증가하는 부분수열 4 (0) | 2023.03.18 |
[백준 14501번] 파이썬 - 퇴사 (0) | 2023.03.12 |
[백준 11049번] 파이썬 - 행렬 곱셈 순서 (0) | 2023.03.01 |