Algorithm/문제

[BOJ/JAVA] 백준 15486번 퇴사2 ( DP )

장용석 2024. 3. 30. 18:24

 

✔ 문제

난이도 : 골드5 🥇

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

 

15486번: 퇴사 2

첫째 줄에 N (1 ≤ N ≤ 1,500,000)이 주어진다. 둘째 줄부터 N개의 줄에 Ti와 Pi가 공백으로 구분되어서 주어지며, 1일부터 N일까지 순서대로 주어진다. (1 ≤ Ti ≤ 50, 1 ≤ Pi ≤ 1,000)

www.acmicpc.net

 

T : 상담하는데 걸리는 기간

P : 상담 했을 때 받을 수 있는 금액

 

N이 주어젔을 때 오늘부터 N+1일째 되는 날 퇴사를 하기 위해서, 남은 N일 동안 최대한 많은 상담을 하려고 한다.

상담을 적절히 했을 때, 얻을 수 있는 최대 수익을 구하는 문제입니다.

 

 

 

✔ 문제 풀이

단순하게 1일~N일, 2일~N일... 모든 경우를 계산하게 되면 N의 범위가 최대 1,500,000이기 때문에 신간초과가 됩니다.

그래서 DP의 특징인 메모이제이션을 통해 중복연산을 줄이면서 문제를 해결해 나가야 합니다.

 

하지만 DP문제는 어떻게 적용하는지 떠올리기가 아직까지는 쉽지 않은 것 같습니다.

그렇기 때문에 다양한 문제를 많이 접하면서 풀어봐야 하는 것 같습니다.

그럼 문제를 풀어보겠습니다.

 

int n = Integer.parseInt(br.readLine());
int[][] schedule = new int[n+2][2];
int[] dp = new int[n+2];
for( int i = 1; i<n+1; i++){
    st = new StringTokenizer(br.readLine());
    int t = Integer.parseInt(st.nextToken());
    int p = Integer.parseInt(st.nextToken());
    schedule[i][0] = t;
    schedule[i][1] = p;
}

💡 n+2

일자를 배열의 인덱스를 통해 표현하기 위해 즉, 인덱스와 일자를 일치시키기 위해 +1,

금액을 완전히 계산되는 날은 n+1일째 이기 때문에 n+1 인덱스에 최종 결괏값을 저장됨으로 +1,

총 n+2 크기의 배열을 선언하였습니다.

 

int max = 0;
for( int i = 1; i<=n+1; i++){
    if( max < dp[i]) max = dp[i];

    int next = i + schedule[i][0];
    int cost = schedule[i][1];
    if( next < n+2 ){
        dp[next] = Math.max(dp[next], max + cost);
    }
}

💡 if( max < dp[ i ] ) max = dp[ i ]

현재 날짜 까지(i) 의 최대 이익을 갱신합니다.

 

💡 dp[ next ] = Math.max( dp[ next ], max + cost )

dp[next] : 이전에 다른 상담 일정을 통해 설정된 next날까지 왔을 때의 이익

( 다른 상담을 선택했을 때의 이익 )

max + cost : 현재 날짜까지의 최대 이익(max)과 현재 상담 비용(cost)을 더한 값

( 현재 상담을 선택했을 때의 이익 )

 

두 가지 값 모두 next날까지의 상담 이익을 의미합니다.

하지만 어떤 상담 일정을 통해 next날까지 왔는지에 따라 상담 이익이 달라지게 되고, 그 이익중 가장 큰 이익을 얻을 수 있는 상담 일정을 선택하는 과정입니다.

 

이렇게 함으로써 현재까지의 최대 이익을 유지하면서, 다음 상담을 고려하여 최대 이익을 갱신할 수 있습니다.

 

 

🔎 전체 코드

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main{
	public static void main(String[] args) throws IOException {
       	BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
        StringTokenizer st;
        
        int n = Integer.parseInt(br.readLine());
        int[][] schedule = new int[n+2][2];
        int[] dp = new int[n+2];
        for( int i = 1; i<n+1; i++){
            st = new StringTokenizer(br.readLine());
            int t = Integer.parseInt(st.nextToken());
            int p = Integer.parseInt(st.nextToken());
            schedule[i][0] = t;
            schedule[i][1] = p;
        }
        
        int max = -1;
        for( int i = 1; i<=n+1; i++){
            if( max < dp[i] ) max = dp[i];
            
            int next = i + schedule[i][0];
            int cost = schedule[i][1];
            if( next < n+2 ){
                dp[next] = Math.max(dp[next], max + cost);
            }
        }
        
        System.out.print(dp[n+1]);
        
	}
}