안녕하세요 오늘 풀어볼 문제는 스티커 입니다.
https://www.acmicpc.net/problem/9465
스티커는 dp 문제인데 기본 DFS에 결합한 형태와는 조금 다른 문제에요.
단순히 2차원 배열을 탐색하며 재귀 호출하는 방식이 아니고 점화식을 정의해줘야 합니다.
점화식을 정의하기 위해 문제를 개념적으로 뜯어보겠습니다.
우선 스티커의 1~n번째 열을 순차로 탐색하는 걸 전제로 할게요.

그리고 지금 k번째 열을 고려하고 있다고 가정할게요.
보라색 네모 부분이 k번째 열입니다.

이 때 고려할 수 있는 경우의 가짓수는 3가지입니다.
1. (k열 0행)을 선택한다.
2. (k열 1행)을 선택한다.
3. 해당 스티커를 선택하지 않는다.
각 경우들의 동작은 잠시 미뤄두고 이번엔 k + 1번째 열을 고려해볼게요.
초록색으로 체크한 부분이 선택한 스티커입니다.


각각 0행과 1행 스티커를 선택한 경우입니다.
이 경우들에서 '반드시 이전 열에서 선택한 행과 다른 행을 선택'해야 한다는 걸 알 수 있습니다.
(k + 1열 0행) 스티커를 선택하려면 k열에서는 1행의 스티커를 선택해야 겠네요.
네, 위에서 고려한
1. (k열 0행)을 선택한다.
2. (k열 1행)을 선택한다.
이 두 경우들이 동작했습니다.
그럼
3. 해당 스티커를 선택하지 않는다.
이 경우는 어떻게 생각해야 할까요?
정답은 (k - 1열 선택한 스티커와 다른 행)의 스티커를 선택하는 것입니다.
이 경우일 때 k열의 어떠한 스티커도 선택하지 않으면서 가장 높은 점수를 가져올 수 있네요.

그런데 이런 의문이 생길 수 있습니다.
'같은 행의 스티커를 가져오면 안될까?'

직관적으로는 괜찮아 보이네요.
하지만 이 경우는 성립하지 않습니다.
왜냐하면 아래 경우에서 이미 (k열 0행)을 선택할 수 없어졌기 때문입니다.

(k - 1열 0행)을 선택 했을 때 (k열 0행)은 경우에서 배제하기 때문에 '고르지 않는다'는 경우도 존재할 수 없는 거죠.
음... 제 설명이 도움이 되고 있으면 좋겠네요.
위 설명을 바탕으로 dp 배열을 정의한다면 아래와 같습니다.
- dp[0][i]: i번째 열의 위쪽 스티커를 선택했을 때의 최대 점수
- dp[1][i]: i번째 열의 아래쪽 스티커를 선택했을 때의 최대 점수
정의를 코드(점화식)으로 나타내면 아래와 같구요,
dp[0][i] = max(dp[1][i - 1], dp[1][i - 2]) + stkr[0][i];
dp[1][i] = max(dp[0][i - 1], dp[0][i - 2]) + stkr[1][i];
i - 1번째 열을 '선택하는 경우'와 '선택하지 않는 경우' 중 큰 점수를 고르는 개념을 아시겠나요?
이제 이 점화식을 반복문에서 돌리면 되는데, i - 2 인덱스를 사용하는 부분이 보이실 거에요,
0번열과 1번열은 초기화를 해줘야 한다는 뜻입니다.
dp[0][0] = stkr[0][0];
dp[1][0] = stkr[1][0];
dp[0][1] = dp[1][0] + stkr[0][1];
dp[1][1] = dp[0][0] + stkr[1][1];
아래는 코드 전문
#include <iostream>
using namespace std;
int T, n;
int stkr[3][100001];
int dp[3][100001];
int main() {
cin.tie(NULL); cout.tie(NULL); ios_base::sync_with_stdio(false);
cin >> T;
while (T--) {
cin >> n;
for (int i = 0; i < 2; i++)
for (int j = 0; j < n; j++)
cin >> stkr[i][j];
dp[0][0] = stkr[0][0];
dp[1][0] = stkr[1][0];
dp[0][1] = dp[1][0] + stkr[0][1];
dp[1][1] = dp[0][0] + stkr[1][1];
for (int i = 2; i < n; i++) {
dp[0][i] = max(dp[1][i - 1], dp[1][i - 2]) + stkr[0][i];
dp[1][i] = max(dp[0][i - 1], dp[0][i - 2]) + stkr[1][i];
}
cout << max(dp[0][n - 1], dp[1][n - 1]) << '\n';
}
}
도움이 되셨다면 공감과 댓글 부탁드립니다.
'Coding Test > Baekjoon' 카테고리의 다른 글
| [C++] 백준 11049: 행렬 곱셈 순서 (동적계획법) (0) | 2025.10.12 |
|---|---|
| [C++] 백준 2143: 두 배열의 합 (0) | 2025.10.10 |
| [C++] 백준 14500: 테트로미노 (0) | 2025.05.10 |
| [C++] 백준 9019: DSLR (0) | 2025.05.10 |
| [C++] 백준 30804: 과일 탕후루 (0) | 2025.05.01 |