본문 바로가기
PS/BOJ

[자바] 백준 14728 - 벼락치기 (java)

by Nahwasa 2024. 4. 8.

문제 : boj14728

 

 

필요 알고리즘

  • DP, 냅색 (배낭 문제)
    • DP로 해결 가능한 문제이다.

※ 제 코드에서 왜 main 함수에 로직을 직접 작성하지 않았는지, 왜 Scanner를 쓰지 않고 BufferedReader를 사용했는지 등에 대해서는 '자바로 백준 풀 때의 팁 및 주의점' 글을 참고해주세요. 백준을 자바로 풀어보려고 시작하시는 분이나, 백준에서 자바로 풀 때의 팁을 원하시는 분들도 보시는걸 추천드립니다.

 

 

풀이

  dp[x]를 x시간을 사용해 얻을 수 있는 최대 점수라고 해보자.

그렇다면 현재 단원에 대한 K와 S가 주어졌을 때, x시간을 사용해 얻을 수 있는 최대 점수는, '현재까지 파악한 x시간을 사용해 얻을 수 있는 최대 점수', 'x-K 시간까지 얻을 수 있는 최대 점수에 이번 단원을 공부하여 얻은 S점을 더한 것' 중에 큰 걸 택하면 된다.

 

  위의 말을 점화식으로 나타내면 dp[x] = max(dp[x], dp[x-K]+S) 이다. 그럼 이걸 그냥 구현하기만 하면 된다. 코드 자체도 그냥 입력받고, 위 수식을 적용하기만 한 것이다. 여기서 for (int i = t; i >= k; i--) 처럼 dp[t]부터 점차 이전시간으로 진행하며 점화식을 적용한 이유는, 그렇게 하지 않으면 현재 보고 있는 단원이 여러번 연산 상에 적용될 수 있기 때문이다.

 

  무슨말이냐면 입력이 아래와 같다고 해보자.

1 100
1 10

 

  당연하게도 0~100 시간 이내에 1의 시간만 사용 가능하며, 답은 '10'이다.

근데 시간이 작은 부분부터 저 수식을 적용하면 답이 '1000'이 나오게 될 것이다. 이걸 처리하기 위해 다른 방식을 적용해도 되지만, 귀찮을 것이므로 그냥 뒤에서 부터 보면 해결된다.

 

 

코드 : github

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

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 1 << 16);

    public static void main(String[] args) throws Exception {
        new Main().solution();
    }

    private void solution() throws Exception {
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int t = Integer.parseInt(st.nextToken());

        int[] dp = new int[t+1];
        while (n-->0) {
            st = new StringTokenizer(br.readLine());
            int k = Integer.parseInt(st.nextToken());
            int s = Integer.parseInt(st.nextToken());

            for (int i = t; i >= k; i--) {
                dp[i] = Math.max(dp[i], dp[i-k] + s);
            }
        }

        System.out.println(dp[t]);
    }
}

 

댓글