본문 바로가기
알고리즘/백준

[백준 9465번 스티커]

by 익명의 문과 개발자 2024. 8. 19.
728x90
728x90

오늘의 문제는 스티커이다.

 

 

#고민의 흐름

처음엔 무조건 완전탐색!

 

처음에 문제를 읽었을 때에는 dfs나 bfs 등으로 한 곳 점수 더하고,

그 칸과 주변까지 방문처리해 주고 반복하는 방식을 떠올렸었다.

 

하지만 n의 구간이 10만까지인 점을 고려하면 무조건 시간초과가 날 것 같았다.

 

어떻게 하는 게 좋을지 고민하던 중 구간별 최고점수를 기록하며 나아가는 Bottom-Up DP 방식이 떠올랐다.

dp 배열을 어떻게 만들지 메모장을 켜고 한참을 고민하다가 문제를 풀었다.

사진과 함께 설명해 나가겠다! ( 예제는 예제 문제 1번을 사용하였다. )

일단, dp배열을 만들 때 이전값을 참고하기 때문에 dp [0]의 경우 Array오류가 날 수 있어 애초에 n + 1으로 선언해 주었다.

또한, arr배열도 매번 Index신경 쓰기 귀찮으니 이것도 1 ~ n+1로 입력을 해주었다.

 

dp배열의 0행, 1행은 각자 교차되는 arr배열의 0행, 1행을 더해준다.

(ex. dp [0][i] = dp [1][i-1] + arr [0][i]; )

 

dp배열의 2행은 1열 이전의 dp배열의 0행과 1행 중 최댓값을 넣어준다.

(ex. dp [2][i] = Math.max(dp [0][i-1], dp [1][i-1]); )

 

✨dp배열 0행과 1행 값들 중 각각 dp배열 2행 + arr배열 0행 or 1행 값보다 작다면 바꿔준다.

(ex. dp [0][i] = Math.max(dp [0][i], dp [2][i-1] + arr [1][i]); )

 

위처럼 dp [0][i]와 dp [1][i]는 각자 교차되는 [i-1]의 값을 더해준다.

 

dp [2][i]는 dp [0][i-1]과 dp [1][i-1] 중 큰 수로!

 

dp배열을 채우다 보면 이렇게 된다.

이제 마지막 칸을 채워야 하는데, 이때 위 규칙 설명 중 ✨이 달려있는 규칙이 적용된다.

( 한 칸 고르지 않은 경우가 더 큰 점수결과를 만드는 경우! )

 

이전 규칙처럼 dp [0][i]와 dp [1][i]를 채운다면 위와 같다.

하지만 위의 ✨규칙을 보자.

 

✨dp배열 0행과 1행 값들 중 각각 dp배열 2행 + arr배열 0행 or 1행 값보다 작다면 바꿔준다.

 

즉, i-1에 점수를 획득하지 않았다면, 200점이고 이번에 arr의 [0]과 [1] 중 아무거나 가능하다는 말이다.

그렇다면 dp [0][i]는 dp [2][i-1] + arr [0][i] = 240 하지만 기존방식이 더 크기 때문에 패스.

dp [1][i]는 dp [2][i-1] + arr [1][i] = 260 현재 dp [1][i]보다 크기 때문에 대체해 준다!

배열을 마저 채워주면 아래와 같다.

 

여기까지 왔다면 dp [0][i]와 dp [1][i] 중 큰 수가 답이 되겠다.

 

 

코드는 다음과 같다.

( 코드가 너무 커 보인다면 "Ctrl + 스크롤 내리기" 하면 잘 보여요! )

( 초기화는 "Ctrl + 0" / 다시 확대는 "Ctrl + 스크롤 올리기" )

import java.util.*;
import java.io.*;
public class Main {
    static StringBuilder sb = new StringBuilder();
    public static void main (String [] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        int tc = Integer.parseInt(br.readLine());
        StringTokenizer st;
        int arr[][], dp[][];
        for(int t = 0; t<tc; t++){
            int n = Integer.parseInt(br.readLine());
            arr = new int [2][n + 1];
            dp = new int [3][n + 1];
            for(int i = 0; i<2; i++){
                st = new StringTokenizer(br.readLine());
                for(int j = 1; j<n + 1; j++){
                    arr[i][j] = Integer.parseInt(st.nextToken());
                }
            }
            //여기까지가 입력 !
            
            //1부터 n까지 배열을 채워간다
            for(int i = 1; i<n + 1; i++){
            	//dp[0]과 dp[1]칸은 교차로 arr값을 더해주며 배열을 채우고,
                dp[0][i] = dp[1][i-1] + arr[0][i];
                dp[1][i] = dp[0][i-1] + arr[1][i];
                
                //dp[2][i-1]값에 각 수를 더한 값이 지금보다 더 크다면 바꾼다.
                dp[0][i] = Math.max(dp[0][i], dp[2][i-1] + arr[0][i]);
                dp[1][i] = Math.max(dp[1][i], dp[2][i-1] + arr[1][i]);
                
                //dp[2][i] 값은 [i-1]의 두 값중 더 큰애로 !
                dp[2][i] = Math.max(dp[0][i-1], dp[1][i-1]);
            }
            
            //출력을 위해 sb에 append! 줄바꿈도 잊지말자.
            sb.append(Math.max(dp[0][n], dp[1][n])).append("\n");
        }
        //출력하면 끝.
        System.out.print(sb);
    }
}

 

DP문제를 만나고 한참을 고민만 하다가 검색찬스를 쓴 경우도 많았는데

이번 문제는 혼자서 DP문제임을 알고, 표도 잘 만들어서 채워나가고 답까지 한 번에 맞춰서 기분이 좋았다.

앞으로 만날 DP문제들도 잘(?) 풀 수 있을 것만 같다.

 

궁금한 점이 있거나 보충할 점이 있다면 언제든 댓글 부탁드립니다 ~

 

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

 

 

728x90

'알고리즘 > 백준' 카테고리의 다른 글

[백준 1987번 알파벳]  (1) 2024.08.22
[백준 1043번 거짓말]  (2) 2024.08.21
[백준 15663번 N과 M (9)]  (2) 2024.08.16
[백준 9251번 LCS]  (0) 2024.08.15
[백준 17626번 Four Squares]  (0) 2024.07.18