[C++] 99클럽 코테 스터디 12일차 TIL + 포도주 시식(백준 2156번)

2025. 4. 15. 20:11·항해99 코테

✅ 오늘의 학습 키워드

  • 다이나믹 프로그래밍 or 동적 계획법 (Dynamic Programming = DP)

✅ 공부한 내용

✔️ 문제 요약

(백준 문제 링크: https://www.acmicpc.net/problem/2156)

포도주 시식회에서 일렬로 놓인 포도주를 마시려고 한다. 다음과 같이 두 가지 조건이 있다.

  1. 선택한 포도주는 모두 마셔야 한다.
  2. 연속으로 3잔을 모두 마실 수 없다.

각 포도주 잔에 들어있는 양이 주어질 때, 최대로 마실 수 있는 포도주의 양을 구하는 문제다.

✔️ 풀이 로직

이 문제는 동적 프로그래밍 접근법으로 해결해야한다.
각 위치에서 가능한 경우의 수를 고려하며 최대값을 누적해 나가는 방식이다.

  1. DP 배열을 정의: dp[i]는 i번째 잔까지 고려했을 때 마실 수 있는 최대 양
  2. 각 위치 i에서 가능한 경우:
    • i번째 잔을 마시지 않는다
    • i번째 잔을 마시고, i-1번째 잔은 마시지 않는다
    • i번째 잔과 i-1번째 잔을 마시고, i-2번째 잔은 마시지 않는다

3. 이를 점화식으로 표현: (❗참고❗ max 함수를 3개 이상 값에 대해 g++로 컴파일을 할 경우, -std=c++11로 해줘야한다. 일단 저는 그랬음... 흠흠..)

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

4. 초기 조건:

if (n >= 1) dp[1] = amount[1]; // 포도주가 1잔만 있을 경우, 그 1잔을 마신다
if (n >= 2) dp[2] = amount[1] + amount[2]; // 포도주가 2잔만 있을 경우, 두 잔 모두 마신다

✅ 오늘의 회고

- 😳 어떤 문제가 있었고, 나는 어떤 시도를 했는지

DP 문제를 잘 몰랐기에 점화식을 이번 기회에 처음 접해봤다. 처음에는 그냥 반복문으로 풀려고 시도했으나, 연속 3잔을 마실 수 없다는 제약 조건을 효율적으로 처리하기 어려웠다. (네! 그래서 답 봤습니다!)

그리고 max 함수 사용법에서도 오류가 있었다. 평소 터미널로 코딩을 하기에 g++로 직접 컴파일을 한다. 하지만 다음과 같은 에러가 뜬다.

이건 C++에서 3개 이상의 값을 비교할 때 initializer list를 사용하려면 C++11 이상의 컴파일러 옵션이 필요하다는 것이다.

- 🤔 어떻게 해결했는지

그래서 g++ -std=c++11 을 해주면 컴파일이 정상적으로 된다. 아니면 중첩된 max 함수를 사용하면 된다고 한다.

즉, 정리하면 !! C++에서 여러 값의 최댓값을 구하는 방법:

  • 중첩된 max 함수: max(a, max(b, c))
  • C++11 initializer list: max({a, b, c}) -> ex) g++ -std=c++11 bj_2156.cpp -o bj_2156

- 🤩 무엇을 새롭게 알았는지

  • DP의 핵심은 '최적 부분 구조'와 '중복되는 부분 문제'를 활용해 효율적으로 해를 구하는 것이다.
    • 최적 부분 구조(Optimal Substructure) - 이 문제는 더 작은 부분 문제의 최적해를 이용해 전체 문제의 최적해를 구할 수 있다. 즉, i번째 포도주까지 고려했을 때의 최대 양은 i-1, i-2, i-3번째 포도주까지 고려했을 때의 최대 양을 이용하여 계산한다.
    • 중복되는 부분 문제(Overlapping Subproblems) - 같은 계산을 여러 번 반복하게 된다. 예를 들어, 각 위치에서 연속 3잔을 마실 수 없다는 제약을 고려하면서 최대 양을 구하려면, 이전 위치들에서의 최대 양을 반복적으로 참조해야 한다.
  • 그리고 점화식을 세운다!!!! (이것도 어렵다!!!)

만약 그리디(Greedy) 알고리즘이나 완전 탐색(Brute Force)으로 풀려고 한다면:

  • 그리디는 지금이 최적인 선택이 전체적으로 최적이라는 보장이 없고 연속 3잔을 마실 수 없기에 이 문제에 적합하지 않다.
  • 완전 탐색은 가능한 모든 조합을 확인해야 하므로 n이 커지면 시간 복잡도가 O(2^n)으로 비효율적이다.

반면 DP는 O(n) 시간 복잡도로 해결할 수 있어 효율적이다. 이 문제는 최적 부분 구조와 중복되는 부분 문제라는 DP 적용의 두 가지 핵심 조건을 모두 만족하기 때문에 DP로 접근하는 것이 자연스럽다.


✅ 전체 코드

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {

    int n; // 포도주 잔의 개수
    cin >> n;

    vector<int> amount(n+1); // 인덱스 1부터 시
    for(int i = 1; i <= n; i++){
        cin >> amount[i]; 
    }

    vector<int> dp(n+1, 0); // DP 배열

    // 연속 2잔까지는 마실 수 있기 때문에 다음과 같은 조건 성립
    if (n >= 1) dp[1] = amount[1]; // 첫 번째 잔의 양이 최대
    if (n >= 2) dp[2] = amount[1] + amount[2]; // 첫 번째와 두번 째잔의 합이 최

    for(int i = 3; i <= n; i++){
        dp[i] = max({
                dp[i-1], // i번째 잔 마시지 않는 경우
                dp[i-2] + amount[i], // i번째 잔은 마시고, i-1번째 잔 X
                dp[i-3] + amount[i-1] + amount[i] // i, i-1번째 잔 마시는 경우
            });    
    }

    cout << dp[n] << endl; // 최대로 마실 수 있는 포도주의 양 출력

    return 0;

}

'항해99 코테' 카테고리의 다른 글

[C++] 99클럽 코테 스터디 14일차 TIL + 진우의 달 여행 (Small) (백준 17484번)  (1) 2025.04.17
[C++] 99클럽 코테 스터디 13일차 TIL + JadenCase 문자열 만들기(프로그래머스 12951번)  (0) 2025.04.16
[C++] 99클럽 코테 스터디 11일차 TIL + 과자 나눠주기(백준 16401번)  (0) 2025.04.14
[C++] 99클럽 코테 스터디 10일차 TIL + 병든 나이트(백준 1783번)  (0) 2025.04.11
99클럽 코테 스터디 9일차 TIL + 저울(백준 2437번)  (0) 2025.04.10
'항해99 코테' 카테고리의 다른 글
  • [C++] 99클럽 코테 스터디 14일차 TIL + 진우의 달 여행 (Small) (백준 17484번)
  • [C++] 99클럽 코테 스터디 13일차 TIL + JadenCase 문자열 만들기(프로그래머스 12951번)
  • [C++] 99클럽 코테 스터디 11일차 TIL + 과자 나눠주기(백준 16401번)
  • [C++] 99클럽 코테 스터디 10일차 TIL + 병든 나이트(백준 1783번)
탱도시락
탱도시락
  • 탱도시락
    코딩도시락
    탱도시락
  • 전체
    오늘
    어제
    • 분류 전체보기 (25)
      • CS50 (4)
      • 항해99 코테 (17)
      • C++ 코딩테스트 준비 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    James Cameron
    항해99
    코딩테스트준비
    코칭스터디 2기
    개발자취업
    코딩테스트 문법
    아스키코드
    2차원 배열
    2진수
    Vector
    부스트코스
    코테
    코딩테스트
    코딩테스트 합격자 되기
    Til
    99클럽
    CS50 코칭스터디 2기
    인간도 모델이다
    시간복잡도
    창작과모방
    2진법
    CS50
    컴퓨터과학
    알고리즘 효율 분석
    배열의 효율성
    컴퓨팅 사고력
    C++
    디지털윤리
    유니코드
    데이터 타입
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
탱도시락
[C++] 99클럽 코테 스터디 12일차 TIL + 포도주 시식(백준 2156번)
상단으로

티스토리툴바