[boj] (s1) 9465 스티커

강신현·2022년 4월 17일
0

✅ dp ✅ Bottom Up

문제

링크

풀이

1. 문제 접근 및 해결 로직 (풀이법)

  • 인접한 스티커는 선택할 수 없다.
    • 대각선에 위치한 스티커만 선택 가능
    • 한 행에 하나의 스티커만 선택 가능
  • 정의
    f(i,j)=i,jf(i,j)=i,j 칸을 마지막으로 골랐을 때 스티커 점수의 최댓값
  • 구하는 답
    max(f(0,n1),f(1,n1)),(0:i,1:j)max(f(0,n-1),f(1,n-1)),(0:i,1:j)
  • 초기값
    f(0,0)=sticker[0][0]f(0,0)=sticker[0][0]
    f(0,1)=sticker[1][0]+sticker[0][1]f(0,1)=sticker[1][0]+sticker[0][1]
    f(1,0)=sticker[1][0]f(1,0)=sticker[1][0]
    f(1,1)=sticker[0][0]+sticker[1][1]f(1,1)=sticker[0][0]+sticker[1][1]
  • 점화식
    f(0,j)=max(f(1,j1),f(1,j2))+sticker[0][j],(j>=2)f(0,j)=max(f(1,j-1),f(1,j-2))+sticker[0][j],(j>=2)
    f(1,j)=max(f(0,j1),f(0,j2))+sticker[1][j],(j>=2)f(1,j)=max(f(0,j-1),f(0,j-2))+sticker[1][j],(j>=2)
  • 구하는 답
    스티커를 떼는 경우는 크게 마지막 행의 윗줄을 뗄 것이냐, 아랫줄을 뗄 것이냐로 나눠질 수 있다.
    왜냐하면 스티커의 점수가 최대가 되려면 일단 많이 떼야하는데 마지막줄을 안뗄 이유가 없기 때문이다.
    따라서 스티커 점수의 최댓값은 마지막 행의 윗줄 or 아랫줄을 떼는 두가지 경우 중에 큰 값이다.

  • 초기값
    예를들어 스티커가 다음과 같이 주어진다면

    ```
    50 10 100 20 40
    30 50 70 10 60
    ```

f(0,0)=50f(0,0)=50
f(0,1)=30+10=40f(0,1)=30+10=40
f(1,0)=30f(1,0)=30
f(1,1)=50+50=100f(1,1)=50+50=100

  • 점화식
(1,j2)(1,j-2)(i,j)(i,j)
(1i,j2)(1-i,j-2)(1i,j1)(1-i,j-1)

(i,j)(i,j) 번째 스티커는 열이 다른 (1i,j2)(1-i,j-2) 번째 스티커와 (1i,j1)(1-i,j-1) 번째 스티커에 따라 결정된다.

왜냐하면 대각선 위치의 스티커만 선택이 가능하고, 모든 행에서 스티커를 선택해야 한다는 조건이 없으므로 (1i,j1)(1-i,j-1) 을 건너뛰고, (1i,j2)(1-i,j-2) 에서 바로 (i,j)(i,j) 로 넘올 수도 있다.

그리고 (1,j2)(1,j-2)을 점화식에 포함시키지 않은 이유는 (1i,j1)(1-i,j-1)에서 (1,j2)(1,j-2)가 이미 포함되기 때문이다.

dp - Bottom Up (반복문, 타뷸레이션) 사용

2. 코드

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>

using namespace std;

int T, n;
int sticker[2][100000];
int memo[2][100000];

int main()
{
    cin >> T;
    while(T--){
        memset(sticker, 0, sizeof(sticker));
        memset(memo, 0, sizeof(memo));

        cin >> n;
        for (int i = 0; i < 2; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cin >> sticker[i][j];
            }
        }

        memo[0][0] = sticker[0][0];
        memo[0][1] = sticker[1][0] + sticker[0][1];
        memo[1][0] = sticker[1][0];
        memo[1][1] = sticker[0][0] + sticker[1][1];

        for (int j = 2; j < n; j++)
        {
            memo[0][j] = max(memo[1][j-1], memo[1][j-2]) + sticker[0][j];
            memo[1][j] = max(memo[0][j - 1], memo[0][j - 2]) + sticker[1][j];
        }

        cout << max(memo[0][n-1], memo[1][n-1]) << "\n";
    }
    
    return 0;
}

3. 시간 복잡도 분석

경우의 수를 모두 구하므로
O(N)O(N)

4. 문제에서 중요한 부분

DP문제는 점화식을 도출하는 것이 중요하다.
Bottm Up(반복문)으로 풀지 Top Down(재귀)으로 풀지는 선택사항

profile
땅콩의 모험 (server)

0개의 댓글

관련 채용 정보