ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 1563번 : 개근상
    알고리즘 공부 2020. 5. 1. 14:55

      초기 조건을 좀 많이 적었다..ㅋㅋㅋ 더 깔끔하게 하는 방법이 있을 수도 있지만.. 그래도 뭐 풀었으면 된 거지


      나는 지각은 마지막에 한 번 고려했다. 그래서 일단 dp를 다음과 같이 정의했다.

     

    dp [n][k] : n일 동안 k번 결석하고 개근상을 받을 수 있는 경우의 수

     

      이런 형태의 문제는 흔하다. 연속되는 계단을 오르지 않거나 하는 문제 등 여러 곳에서 볼 수 있다. 이 경우 결석을 연속 세 번은 할 수 없다.

     

    1. n일 째에 출석하는 경우 = dp [n-1][k]

    이 경우 n-1일 동안 k번의 결석을 해야 하는데 어차피 마지막 날에 출석할 것이기 때문에 아무런 제약이 없다.

     

    2. n일 째에 결석하는 경우

    n일째에 결석하는 경우 연속으로 3번 결석할 수 있기 때문에 좀 더 세부적으로 경우를 나눠야 한다.

      2.1. n-1일째에 출석하고 n일째에 결석하는 경우 = dp [n-2][k-1]

      이 경우 n-1일째에 출석을 했으므로 n-2일 동안 k-1번의 결석을 아무런 제약 없이 하면 된다.

      2.2. n-1일째에 결석하고 n일째에 결석하는 경우 = dp [n-3][k-2]

      이 경우 n-2일째에도 결석을 하면 연속 세 번 결석이므로 반드시 n-2일째에는 출석을 해야 한다. 따라서 n-3일 동안 k-2번의 결석을 아무런 제약 없이 하면 된다.

     

    dp [n][k] = dp [n-1][k] + dp [n-2][k-1] + dp [n-3][k-2]

     

      이렇게 dp를 계산하고 나면 n일 동안 k번의 결석을 하면서 개근상을 받을 수 있는 경우의 수가 구해진다. 이제 여기서 지각을 고려해주면 되는데 지각은 아예 안 하거나 딱 한 번만 해야 한다.

     

    1. 지각을 아예 안 하는 경우 = dp [n][k]

    2. 지각을 한 번만 하는 경우 = (n-k) * dp [n][k]

     

      지각을 한 번 할 경우에는 기존의 출석이었던 하나를 지각으로 교체할 수 있다. 그 경우의 수는 출석한 횟수(n-k)와 같기 때문에 (n-k)를 곱해주면 된다.

     

    #include <iostream>
    
    using namespace std;
    
    int n;
    int dp[1002][1002];
    int DIV = 1000000;
    
    int main()
    {
        cin >> n;
        
        dp[0][0] = 1;
        dp[1][0] = 1;
        dp[1][1] = 1;
        dp[2][0] = 1;
        dp[2][1] = 2;
        dp[2][2] = 1;
        dp[3][0] = 1;
        dp[3][1] = 3;
        dp[3][2] = 3;
        
        for(int i = 4; i <= n; i++)
        {
            for(int j = 0; j*1.5 <= i+1; j++)
            {
                if(i-1 >= 0 && j >= 0)   dp[i][j] = (dp[i][j] + dp[i-1][j]) % DIV;
                if(i-2 >= 0 && j-1 >= 0) dp[i][j] = (dp[i][j] + dp[i-2][j-1]) % DIV;
                if(i-3 >= 0 && j-2 >= 0) dp[i][j] = (dp[i][j] + dp[i-3][j-2]) % DIV;
            }
        }
        
        int ans = 0;
        
        for(int i = 0; i <= n; i++)
        {
            ans = (ans + (dp[n][i] * (n-i+1)) % DIV) % DIV;
        }
        
        cout << ans;
    
        return 0;
    }

    '알고리즘 공부' 카테고리의 다른 글

    백준 1695번 : 팰린드롬 만들기  (0) 2020.05.03
    백준 2662번 : 기업투자  (0) 2020.05.02
    백준 2482번 : 색상환  (0) 2020.04.30
    백준 2624 : 동전 바꿔주기  (0) 2020.04.28
    백준 2602번 : 돌다리 건너기  (0) 2020.04.27
Designed by Tistory.