백준의 포도주시식(2156) 문제이다.

( 문제 바로가기 )



( 문제를 다시 푸는 과정에서 보다 상세한 설명을 다시 포스팅 해놓았습니다. 이 글을 읽으셔도 무관하지만, 보다

  구체적인 설명을 원하시는 분들은 아래의 링크를 타고 가시면 됩니다 ! )

   [ 백준(2156) 포도주 시식 ]


[ 문제설명 ]

- 포도주의 전체 종류의 갯수와, 그 종류별로 들어있는 양이 입력으로 주어진다.

- 포도주를 연속으로 3잔 마실 수 없을 때, 가장 많이 먹을 수 있는 양을 출력시키면 된다.


[ 문제풀이 ]

1) 포도주의 양을 저장하는 배열 Arr와 최댓값을 저장하는 DP배열을 사용한다.

2) Arr[N] = N번째 포도주의 양을 의미하고, DP[N] = N번째 까지의 마신 포도주의 최대 양을 의미한다.

3) 초기식을 구해보면 DP[1] = Arr[1]이 된다. (배열 0번 사용 안했음 ! ==> DP[0] = Arr[0] = 0)

   DP[2] = Arr[1] + Arr[2]가 된다. (두번째 포도주잔 까지의 최대양 = 당연히 첫번째 포도주의양 + 두번째 포도주의 양)

   DP[3] = ??

   3잔을 연속해서 마실 수 없기 때문에, DP[3] = Arr[1] + Arr[2] + Arr[3]으로 표현할 수가 없다. 이 경우에는 조건에

   위배되기 때문이다. 생각해보면 3번째 잔까지의 포도주의 최대 양은...

   "1번째잔 + 3번째잔" or "2번째잔 + 3번째잔" or "1번째잔 + 2번째 잔" 3개 중 최대양이 된다.

   그럼 N번째 잔을 마실 때 최대양을 생각해보자.

   N번째 잔을 마실 때 최대양은 " N-3번째 잔 까지의 최댓값 + N-1번째 잔 + N번째 잔 " or 

    " N-2번째 잔 까지의 최댓값 + N번째 잔 " or " N-1번째 잔 까지의 최댓값 "

   어떻게 N번째 잔이 존재하는데, N-1번째 잔까지의 최댓값이 최대가 될 수 있을까??? 

   극단적으로 예를 들어보자면, N = 6이고 포도주의 양이 0 1 2 200 200 1 이라고 해보자.

   이 경우, 최댓값은 1+200+200 = 401이 되는데, 이 경우는 N번째 잔을 포함하지 않은 것이다. 그럼 N번째 잔을 포함한다고

   생각해보면, 가장 마지막 1이 포함되어야 하고, 최댓값은 1 + 2+ 200 + 1이 되어서 204 밖에 나오지 않을 것이다.

   따라서, N번째 잔을 꼭 선택해야 하는 문제가 아니기 때문에, N-1번째 까지의 최댓값이 최대가 될 수 있는 것이다.

4) 위의 식을 토대로, 점화식을 세워보면

   DP[i] = DP[i - 3] + Arr[i - 1] + Arr[i] vs DP[i - 2] + Arr[i] vs DP[i - 1] 이 3개의 값 중 최댓값이 된다.


[ 소스코드 ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<iostream>
#include<cstring>
 
#define endl "\n"
#define MAX 10000 + 1
using namespace std;
 
int N;
int Arr[MAX];
int DP[MAX];
 
int Bigger(int A, int B) { if (A > B) return A; return B; }
 
void Initialize()
{
    memset(Arr, 0sizeof(Arr));
    memset(DP, 0sizeof(DP));
}
 
void Input()
{
    cin >> N;
    for (int i = 1; i <= N; i++)
    {
        cin >> Arr[i];
    }
}
 
void Solution()
{
    DP[0= Arr[0= 0;
    DP[1= Arr[1];
    DP[2= Arr[1+ Arr[2];
    // 3잔 연속 마실 수 없다.
    // 1. 마지막 잔을 기준으로 3번째 앞에 잔을 마시고, 2번째 앞에 잔을 건너뛰고 1번째 앞에 잔 + 마지막잔 
    // 2. 마지막 잔을 기준으로 2번째 앞에 잔을 마시고 + 마지막 잔
    // 3. 마지막 잔을 마시지 않고, 1번째 앞에 잔의 최댓값
    for (int i = 3; i <= N; i++)
    {
        DP[i] = Bigger(DP[i - 3+ Arr[i - 1+ Arr[i], Bigger(DP[i - 2+ Arr[i], DP[i - 1]));
    }
}
 
void Solve()
{
    Initialize();
    Input();
    Solution();
 
    cout << DP[N] << endl;
}
 
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    //freopen("Input.txt", "r", stdin);
    Solve();
 
    return 0;
}
cs


'[ BOJ Code ] > # BOJ -' 카테고리의 다른 글

[ 백준 2579 ] 계단오르기 (C++)  (3) 2018.11.29
[ 백준 2193 ] 이친수 (C++)  (0) 2018.11.29
[ 백준 1932 ] 정수 삼각형 (C++)  (0) 2018.11.29
[ 백준 1912 ] 연속합 (C++)  (0) 2018.11.29
[ 백준 1463 ] 1로 만들기 (C++)  (0) 2018.11.28

+ Recent posts