[BOJ][C++] 2342번 Dance Dance Revolution

안녕하세요.

오늘은 백준 2342번: Dance Dance Revolution(링크)  문제를 풀어보려고 합니다.

 

문제

승환이는 요즘 "Dance Dance Revolution"이라는 게임에 빠져 살고 있다. 하지만 그의 춤 솜씨를 보면 알 수 있듯이, 그는 DDR을 잘 하지 못한다. 그럼에도 불구하고 그는 살을 뺄 수 있다는 일념으로 DDR을 즐긴다.
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을 넘지 않는다.

 

출력

한 줄에 모든 지시 사항을 만족하는 데 사용되는 최소의 힘을 출력한다.

 

예제 입력

1 2 2 4 0

 

예제 출력

8

 

제한

시간 제한: 2초

메모리 제한: 128MB

 


풀이

처음에는 그냥 그리디하게 풀면 될 수 있을 것 같았는데, 틀렸다고 나와서 다시 생각을 해보았다.

 

현재 값을 구할 때, 이전 값을 이용해서 구하는 방향으로 생각하여 이어나가보았다.

현재 지시 사항에 왼발 혹은 오른발을 했을 때의 최소 힘은, 이전 지시 사항에서의 최소 힘일 때의 경우를 고려해서 계산할 수 있다.

 

즉, 다이나믹 프로그래밍을 이용하면 되는 문제라고 보았다.

 

그래서 처음에 2차원 dp 배열을 만들어서 "dp[i][foot] = i번째 지시 사항을 왼발/오른발로 했을 때 최소 힘" 이라고 정의했다. 그리고 점화식은 아래처럼 이전 값을 사용해서 나타내었다.

 

 

그러나 이렇게 해도 틀렸습니다가 나와서 계속 고민해보다 결국 다른 글을 참고했다.

 

다른 사람들 모두 2차원 배열이 아닌 3차원 dp 배열을 만들어서 작성했다.

https://kibbomi.tistory.com/126

 

boj, 백준) 2342. Dance Dance Revolution ( C / C++)

 

kibbomi.tistory.com

https://barbera.tistory.com/37

 

백준 2342번 - Dance Dance Revolution

https://www.acmicpc.net/problem/2342 2342번: Dance Dance Revolution 입력은 지시 사항으로 이루어진다. 각각의 지시 사항은 하나의 수열로 이루어진다. 각각의 수열은 1, 2, 3, 4의 숫자들로 이루어지고, 이 숫자

barbera.tistory.com

 

정리해보면 아래와 같이 dp를 정의하고 점화식을 세울 수 있다.

 

 

dp를 풀 때, 2차원 배열도 안되면 확장시켜서 3차원 배열로 생각해보자.

특히 문제의 조건을 보면 힌트를 얻을 수 있다.

문제에서 조건이 i번째 지시 사항, 왼쪽 발, 오른쪽 발 3개이기 때문에 자연스레 3차원 배열을 떠올리면 좋을 것 같다.

정답

더보기
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
using ll = long long;
using pr = pair<int, int>;
int inf = 9999999;
int dp[100001][5][5];
int cost[5][5];
vector<int> list;
int n;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    while (1) {
        int next; cin >> next;
        if (next == 0) break;
        list.push_back(next);
    }
    n = list.size();

    for (int i = 1; i <= 4; i++) {
        cost[0][i] = 2;
        cost[i][i] = 1;
    }
    cost[1][2] = 3; cost[1][3] = 4; cost[1][4] = 3;
    cost[2][1] = 3; cost[2][3] = 3; cost[2][4] = 4;
    cost[3][1] = 4; cost[3][2] = 3; cost[3][4] = 3;
    cost[4][1] = 3; cost[4][2] = 4; cost[4][3] = 3;

    memset(dp, inf, sizeof(dp));
    dp[0][0][0] = 0;
    int ans = inf;
    for (int i = 0; i < n; i++) {
        int next = list[i];
        for (int l = 0; l < 5; l++) {
            for (int r = 0; r < 5; r++) {
                dp[i+1][l][next] = min(dp[i+1][l][next], dp[i][l][r] + cost[r][next]);
                dp[i+1][next][r] = min(dp[i+1][next][r], dp[i][l][r] + cost[l][next]);
            }
        }
    }
    for (int l = 0; l < 5; l++) {
        for (int r = 0; r < 5; r++) {
            ans = min(ans, dp[n][l][r]);
        }
    }
    cout << ans;
    return 0;
}

이렇게 해서 백준 2342번 Dance Dance Revolution 문제를 풀어보았습니다.

 

댓글로 질문을 남기시면 성실히 답해드리겠습니다

 

감사합니다!

'PS > 백준 문제' 카테고리의 다른 글

[BOJ][C++] 1562번 계단 수  (0) 2024.10.26
[BOJ][C++] 11401번 이항 계수 3  (0) 2024.10.26
[BOJ][C++] 11444번 피보나치 수 6  (0) 2024.10.14
[BOJ][C++] 10830번 행렬 제곱  (0) 2024.10.14
[BOJ][C++] 7579번 앱  (2) 2024.10.13