[python/백준/DP] 9465 : 스티커

Use_Silver·2022년 2월 19일
0

Algorithm

목록 보기
12/31

스티커

문제

상근이의 여동생 상냥이는 문방구에서 스티커 2n개를 구매했다. 스티커는 그림 (a)와 같이 2행 n열로 배치되어 있다. 상냥이는 스티커를 이용해 책상을 꾸미려고 한다.

상냥이가 구매한 스티커의 품질은 매우 좋지 않다. 스티커 한 장을 떼면, 그 스티커와 변을 공유하는 스티커는 모두 찢어져서 사용할 수 없게 된다. 즉, 뗀 스티커의 왼쪽, 오른쪽, 위, 아래에 있는 스티커는 사용할 수 없게 된다.

모든 스티커를 붙일 수 없게된 상냥이는 각 스티커에 점수를 매기고, 점수의 합이 최대가 되게 스티커를 떼어내려고 한다. 먼저, 그림 (b)와 같이 각 스티커에 점수를 매겼다. 상냥이가 뗄 수 있는 스티커의 점수의 최댓값을 구하는 프로그램을 작성하시오. 즉, 2n개의 스티커 중에서 점수의 합이 최대가 되면서 서로 변을 공유 하지 않는 스티커 집합을 구해야 한다.

위의 그림의 경우에 점수가 50, 50, 100, 60인 스티커를 고르면, 점수는 260이 되고 이 것이 최대 점수이다. 가장 높은 점수를 가지는 두 스티커 (100과 70)은 변을 공유하기 때문에, 동시에 뗄 수 없다.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 두 줄에는 n개의 정수가 주어지며, 각 정수는 그 위치에 해당하는 스티커의 점수이다. 연속하는 두 정수 사이에는 빈 칸이 하나 있다. 점수는 0보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

각 테스트 케이스 마다, 2n개의 스티커 중에서 두 변을 공유하지 않는 스티커 점수의 최댓값을 출력한다.

풀이

  • dp문제에서는 규칙을 찾는것이 중요하므로, case를 나누어 문제를 풀어보았다.

Case 1. 한 칸 떨어진 대각선 숫자 더하기
그림과 같이 일정한 간격의 대각선으로 더하는 규칙은 반례가 존재한다.
쉬운 이해를 돕기 위해 극단적인 예시를 들어보겠다. 여기서 최댓값은 1000과 1000을 더한 2000이다. 즉, 한 칸 떨어진 대각선 이외에 두 칸 떨어진 대각선도 고려해야한다는 것이다.

Case 2. 한 칸 떨어진 대각선 숫자와 두 칸 떨어진 대각선 숫자 중 최댓값을 더하기

단계별 최대값을 구하는 알고리즘
이렇게 숫자가 있다 가정했을 때, 
50	10	100	20	40
30	50	70	10	60

각 위, 아래 인덱스는 대각선의 값만 더할 수 있음 
분리해서 생각해보면 
50	10 
30	50

인덱스 1번 까지만 존재한다 가정,  10이 가질 수 있는 최대는 30
                              50이 가질 수 있는 최대는 50이다.
                              
인덱스 2번 까지만 존재한다 가정,  100이 가질 수 있는 값은 (대각선 값)
                                1) 30   
                                2) 50 + 50
                                최대값은 2) 이므로 50+50을 선택 
                                70이 가질 수 있는 값은 
                                50, 10+30 중 MAX인 50이다.  
50	10+30	100	
30	50+50	70
인덱스 3번 까지만 존재한다 가정,  100이 가질 수 있는 값은 (대각선 값)
                                1) 30   
                                2) 50 + 50
                                최대값은 2) 이므로 50+50을 선택 
                                70이 가질 수 있는 값은 
                                50, 10+30 중 MAX인 50이다.  
50	10+30	100+50+50 20        20이 가질 수 있는 값 중 MAX = 70 + 50	
30	50+50	70+50	10          10이 가질 수 있는 값 중 MAX = 100+50+50 

인덱스 4번도 동일하게 반복 
50	10+30	100+50+50 20+70+50	40
30	50+50	70+50	10+100+50_50 60 

4번 반복 수행 결과

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

마지막 인덱스의 수행 내용은 모든 인덱스 값에서 가능한 선택지 중 최대값을 고려한 값
따라서 마지막 4번 인덱스에서 가장 큰 값을 선택한다. 
60+100+50+50 > 40+10+100+50+50 이므로 
최대값은 260이 된다 

그림으로 정리하자면 다음과 같다.

코드

t = int(input())

for i in range(t):
    n = int(input())
    dp = [list(map(int, input().split())) for _ in range(2)]
	
    if n == 1:
        print(max(dp[0][0], dp[1][0]))

    else:
        dp[0][1] += dp[1][0]
        dp[1][1] += dp[0][0]

        for i in range(2,n):
            dp[0][i] += max(dp[1][i-1], dp[1][i-2])
            dp[1][i] += max(dp[0][i-1], dp[0][i-2])
        print(max(dp[0][n-1], dp[1][n-1]))

n은 1일 때 고려해줘야 함. (n은 1일 때 고려하지 않으면 런타임 에러 오류 발생함)

profile
과정은 힘들지만😨 성장은 즐겁습니다🎵

0개의 댓글