#문제

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

 

9465번: 스티커

문제 상근이의 여동생 상냥이는 문방구에서 스티커 2n개를 구매했다. 스티커는 그림 (a)와 같이 2행 n열로 배치되어 있다. 상냥이는 스티커를 이용해 책상을 꾸미려고 한다. 상냥이가 구매한 스티커의 품질은 매우 좋지 않다. 스티커 한 장을 떼면, 그 스티커와 변을 공유하는 스티커는 모두 찢어져서 사용할 수 없게 된다. 즉, 뗀 스티커의 왼쪽, 오른쪽, 위, 아래에 있는 스티커는 사용할 수 없게 된다. 모든 스티커를 붙일 수 없게된 상냥이는 각 스티커에 점

www.acmicpc.net

 

#작성 코드

TOP-DOWN

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
#include <iostream>
using namespace std;
 
int t, n;
int sticker[2][100000];
int dp[100000][3];
            //[0] : 이전 열에서 아무것도 떼지 않았음
            //[1] : 이전 열에서 상단 스티커를 뗐음
            //[2] : 이전 열에서 하단 스티커를 뗐음 
 
int cal(int col, int status){
    if( col==n )
        return 0;    // n+1열에는 뗄 스티커가 존재하지 않으므로 0을 리턴. 
    if( dp[col][status]!=-1)
        return dp[col][status];
    
    // 1. 아무것도 떼지 않고 다음 열으로 넘어가는 경우 
    int result = cal(col+10);
    // 2. 이전 열의 하단 스티커를 떼지 않았을 경우 -> 하단 스티커도 뗄 수 있다 
    if( status!=2 ){
        result = max(result, sticker[1][col]+cal(col+12));
    }
    // 3. 이전 열의 상단 스티커를 떼지 않았을 경우 -> 상단 스티커도 뗄 수 있다
    if( status!=1 ){
        result = max(result, sticker[0][col]+cal(col+11));
    }
    return dp[col][status] = result; 
}
 
int main(){
    cin>>t;
    while(t--){
        // dp배열을 -1로 초기화한다. 
        for(int i=0; i<100000; i++){
            for(int j=0; j<3; j++){
                dp[i][j] = -1;
            }
        }
        cin>>n;
        for(int i=0; i<2; i++){
            for(int j=0; j<n; j++){
                cin>>sticker[i][j];
            }
        }
        
        // 0열. 0열 이전 열에서 아무것도 떼지 않은 상태에서 시작한다. 
        cout<<cal(00)<<'\n';
    }
    return 0;
}
cs

BOTTOM UP

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
#include <iostream>
using namespace std;
 
int t, n;
int sticker[2][100000];
int dp[100000][3];
            //[0] : 이전 열에서 아무것도 떼지 않았음
            //[1] : 이전 열에서 상단 스티커를 뗐음
            //[2] : 이전 열에서 하단 스티커를 뗐음 
 
int main(){
    cin>>t;
    while(t--){
        // dp배열을 0으로 초기화한다. 
        for(int i=0; i<100000; i++){
            for(int j=0; j<3; j++){
                dp[i][j] = 0;
            }
        }
        cin>>n;
        for(int i=0; i<2; i++){
            for(int j=0; j<n; j++){
                cin>>sticker[i][j];
            }
        }
        
        for(int i=0; i<n; i++){
            // 다음에 아무것도 안떼는 경우, xx, 1x, 2x의 경우 중 최댓값 선택 
            dp[i+1][0= max(dp[i+1][0], max(dp[i][0], max(dp[i][1], dp[i][2])));
            // 다음에 상단 스티커를 떼는 경우, x1, 21의 경우 중 최댓값 선택 
            dp[i+1][1= max(dp[i+1][1], max(dp[i][0], dp[i][2])+sticker[0][i]);
            // 다음에 하단 스티커를 떼는 경우, x2, 12의 경우 중 최댓값 선택
            dp[i+1][2= max(dp[i+1][2], max(dp[i][0], dp[i][1])+sticker[1][i]); 
        }
        
        // n열까지 스티커를 뗀 경우 중 최댓값을 가지는 경우를 출력한다. 
        cout<<max(dp[n][0], max(dp[n][1], dp[n][2]))<<'\n';
    }
    return 0;
}
cs

 

##

2n개의 스티커 중, 스티커를 최대한 많이 뗀다면 n개의 스티커를 뗄 수 있다.

이렇게 생각하면 2개의 선택지밖에 없고, 최적해가 포함되지 않는 경우가 발생할 수도 있다.

-> 모든 경우를 살펴보아야한다.

dp[col][status]에 현재까지 뗀 스티커의 가치의 합을 저장한다.

status = col-1열에서 스티커를 뗀 상태

           : 0 = col-1에서 스티커 안뗐음

           : 1 = col-1 상단 스티커 뗐음

           : 2 = col-1 하단 스티커 뗐음

dp[col][status] 배열은 계산 중에 나타날 수 없는 값인 -1로 초기화하고, 이미 계산된 값을 요구한다면 메모이제이션 한 값을 리턴해준다.

'BOJ' 카테고리의 다른 글

BOJ 11052번 :: 카드 구매하기  (0) 2020.02.03
BOJ 1699번 :: 제곱수의 합  (0) 2020.02.02
BOJ 2618번 :: 경찰차  (0) 2020.02.01
BOJ 10942번 :: 팰린드롬?  (0) 2020.01.28
BOJ 2261번 :: 가장 가까운 두 점  (0) 2020.01.27

+ Recent posts