알고리즘 모음(C++)

백준 4811 - 알약(C++) 본문

백준

백준 4811 - 알약(C++)

공대생의 잡다한 사전 2023. 7. 31. 20:45

문제 링크입니다. https://www.acmicpc.net/problem/4811

 

4811번: 알약

입력은 최대 1000개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스는 한 줄이며, 병에 들어있는 약의 개수 N ≤ 30 가 주어진다. 입력의 마지막 줄에는 0이 하나 주어진다.

www.acmicpc.net

N일이 주어졌을 때, 알약을 먹을 수 있는 방법의 경우를 구하는 문제입니다.

 

온전한 약을 꺼낸 뒤, 반을 먹고 반은 내려놓는 행위는 W, 반이 남은 알약을 꺼내 먹는 행위를 H라고 합니다.

 

1일만 약을 먹는다고 했을 때, 나올 수 있는 경우는

WH인 1개뿐이며

2일만 약을 먹는다고 했을 때, 나올 수 있는 경우는

WHWH, WWHH으로 2개가 됩니다.

3일의 경우에는

WHWHWH, WWHHWH, WHWWHH, WWWHHH, WWHWHH로 5개가 됩니다.

 

여기서 먼저 찾을 수 있는 것은

시작은 무조건 W, 끝은 무조건 H라는 점입니다.

 

그렇다면 3개의 경우는 나눠서 확인한다면

1. W -- H로 끝나는 경우

2. WW -- H로 끝나는 경우

3. WWW -- H로 끝나는 경우

이렇게 W기준으로 3개로 나눌 수 있습니다.

 

3일차의 경우에는 W, H가 각각 3개씩 무조건 있어야 한다는 것을 생각하면

각 경우마다 (W*2, H*2), (W*1, H*2), (W*0, H*2)의 경우를 더하는 것과 같아집니다.

 

그렇다면 4일의 경우에는 W*4, H*4개가 필요하니

W -- H / WW -- H / WWW -- H / WWWW -- H인 경우로 나눈 뒤, 

(W*3, H*3), (W*2, H*3), (W*1, H*3), (W*0, H*3)의 경우를 더해준 값이 됩니다.

 

따라서 [W의 개수][H의 개수]의 배열을 만든 뒤, 해당 값들을 저장해주면서 풀어주면 된다는 결론이 나옵니다.

 

저는 경우를 나눌 때, W를 기준으로 나눴기 때문에 W < H인 경우가 몇개가 나오는지만 확인해주면 됩니다.

W가 1개, H가 N개인 경우에는 W의 위치에 따라서 경우가 달라집니다. 이때 W는 N개의 곳에 위치할 수 있기에 [1][X] = X입니다.

 

W가 2인 경우에는 경우를 나눠서 생각해야합니다.

W*2, H*5인 경우라면, 해당 경우가 W or H로 시작하는 경우로 나눠야합니다.

따라서 W가 먼저 시작했다면, [1][5]의 경우가 될 것이며, H가 먼저 시작했다면 [2][4]의 경우가 될 것입니다. 이 둘을 더하면 됩니다.

 

이를 점화식으로 생각해보면

1. W < H인 경우 -> [X][Y]일 때, [X-1][Y] + [X][Y-1]의 값을 대입해준다.

2. W == H 인 경우 -> [X][Y]일 때, [0~X-1][Y-1]의 값을 전부 더해준다.

 

W개수/H개수 0 1 2 3 4 5 6
0 1 1 1 1 1 1 1
1   1 2 3 4 5 6
2     2 5 9 14 20
3       5 14 28 48
4         14 42 90
5           42 132
6             132

자세한 것은 코드를 참고해주세요.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#define INF 987654321

using namespace std;

long long pill[31][31];
int N;

void solve(){
    for(int i = 0; i <= 30; i++) pill[0][i] = 1;
    for(int i = 1; i <= 30; i++){
        for(int j = i; j <= 30; j++){
            if(i == j){
                for(int k = 0; k < i; k++) pill[i][j] += pill[k][j-1];
            }
            else{
                pill[i][j] = pill[i-1][j] + pill[i][j-1];
            }
        }
    }
}

int main(){
    cin.tie(0);
    cout.tie(0);
    solve();
    while(1){
        cin >> N;
        if(N == 0) break;
        cout << pill[N][N] << "\n";
    }
    return 0;
}

 

 

질문 및 조언은 댓글을 남겨주세요.

'백준' 카테고리의 다른 글

백준 15681 - 트리와 쿼리(C++)  (0) 2023.08.01
백준 2240 - 자두나무(C++)  (0) 2023.07.31
백준 10164 - 격자상의 경로(C++)  (0) 2023.07.27
백준 16194 - 카드 구매하기(C++)  (0) 2023.07.27
백준 2302 - 극장 좌석(C++)  (0) 2023.07.27