문제

https://www.acmicpc.net/problem/2156

 

2156번: 포도주 시식

효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규

www.acmicpc.net


요약

조건을 만족하게 포도주를 선택해서 총량의 최대값 구하기

 

조건1: 나눠 마시기 불가 

조건2: 연속 3잔 불가

 


풀이

단서

1. 최댓값을 구하는 문제

2. 포도주를 하나씩 늘려가면서, i번째 포도주를 선택O or 선택X 하는 경우로 생각 가능 -> 규칙 찾기 가능

 

일반적인 DP 문제로 짐작 가능

=> 규칙을 먼저 찾자

=> DP니까 dp 변수 설정, 초기값, 점화식 수립할 것 염두

 

 

예시

먼저 예시를 들어보자

 

<포도주 총 개수 N=1 일 때>

경우의 수는 다음과 같다

1. 1번째 포도주 선택O 

2. 1번째 포도주 선택X 

 

최대: 무조건 포도주 선택하는 경우(1번)가 최대값임

 

<포도주 총 개수 N=2 일 때>

- 경우의수

1. XX

2. XO

3. OX

4. OO

 

최대: 무조건 모든 포도주 선택(4번)하는 게 최대값

 

<포도주 총 개수 N=3일 때>

여기서부터 문제 조건에 걸리는 것들이 나온다.(3개 연속 선택 불가능함)

- 경우의 수

1. XXX

2. XXO

3. XOX

4. OXX

5. OOX

6. OXO

7. XOO

 

최대: 여기부턴 고정 X(5, 6, 7번 중 하나)

 

N=1, N=2까지만 초기값으로 설정하자.

 

 

이제 실제 예시를 들어보자

6,10,13,9,8,1이라는 포도주 들어 있는 걸 테이블로 나타내면,

 

6 10 13 9 8 1
1번째 ... i-3번째 i-2번째 i-1번째 i번째

 

<포도주의 총 개수가 N=6일때>

일단 배열 2개를 준비한다. arr배열에는 포도주 값을 담고, dp배열엔 각 요소까지 갔을 때 최대값이 담겨있다고 하자.

 

끝 부분만 보면

- i번째 선택 안할 경우

1. ???OOX

2. ???OXX

3. ???XOX

4. ???XXX 

 

끝부분이 선택 안될 때, '3개 연속이 되면 안 된다'는 문제 조건에 위반될 일이 없다. 즉, i-1번째까지의 최대값과 같다.

점화식을 세워보면,

 

dp[i] = dp[i-1]

 

- i번째 선택 할 경우

1.???XXO 

2.???XOO

3.???OXO

 

점화식으로 나타내자

 

1, 3번 -> i-2 번째까지의 최대값 + i번째 값  -> dp[i] = dp[i-2] + arr[i]

2번 -> i-3 번째까지의 최대값 + i-1번째의 값 + i번째의 값 -> dp[i] = dp[i-3] + arr[i-1] + arr[i]

 

결국 dp[i] 는

1. dp[i-1]

2. dp[i-2] +arr[i]

3. dp[i-3] +arr[i-1] +arr[i]

1, 2, 3 중에 최대값이 될 것이다.

 

결론

1. 변수: arr배열, dp배열

2. 초기식

dp[1] = arr[1]
dp[2] = arr[1]+arr[2]

3. 점화식 

max(dp[i-1], dp[i-2] +arr[i], dp[i-3] +arr[i-1] +arr[i])

 


구현

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <algorithm>
using namespace std;

int main(){
    
    //1. 변수 설정
    int n;
    int arr[10001] = { 0, }; //포도주 양
    int dp[10001] = { 0, }; //인덱스 번째까지 포도주 최대 합
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {
        scanf("%d",&arr[i]);
    }

    //2. 초기식
    dp[1] = arr[1];
    dp[2] = arr[1] + arr[2];

    //3. 점화식
    for (int i = 3; i <= n; i++) {
        dp[i] = max(dp[i - 3] + arr[i - 1] + arr[i], max(dp[i - 1], dp[i - 2] + arr[i]));
       
    }

    printf("%d", dp[n]);
    
    return 0;   
}

 

'Problem Solving > BOJ' 카테고리의 다른 글

[백준][JAVA] 2468 안전영역  (0) 2024.09.04