백준 2240 자두나무 자바

꾸준하게 달리기~·2023년 10월 10일
0
post-thumbnail

문제는 다음과 같다.
https://www.acmicpc.net/problem/2240


풀이는 다음과 같다.

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String args[]) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        //자두는 하나의 나무 아래에 서 있다가 다른 나무 아래로 빠르게(1초보다 훨씬 짧은 시간에) 움직일 수 있다.
        //최악의 경우를 생각해보자. T는 1000이고, 움직일 수 있는 횟수는 30이다.
        //자두는 1초보다 훨씬 짧은 시간에 움직일 수 있다고 했으므로, 정해진 하나의 초에 W회를 다 움직이는 것도 가능하다.
        //그렇다면, 경우의 수는 1000^30 이 된다. (움직일 수 있는 1회당 1000초가 존재하고, 30회를 움직일 수 있으므로)
        //2초, 2억번을 아득히 뛰어넘는다.
        //그렇다면, 문제는 DP로 접근해야 한다.
        
        StringTokenizer st = new StringTokenizer(br.readLine()); //첫줄 입력
        int T = Integer.parseInt(st.nextToken());
        int W = Integer.parseInt(st.nextToken());
        
        int[] arr = new int[T+1]; //t미터에 떨어지는 자두의 위치 입력
        for(int i = 1 ; i <= T ; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }
        
        int[][] D = new int[T+1][W+1]; //T미터에 W만큼 이동했을 때의 얻을 수 있는 자두의 최댓값, 다이나믹 프로그래밍.
        
        
        // D 채우기
        for(int t = 1 ; t <= T ; t++) {
            int cur = arr[t];

            //한번도 이동하지 않은것은 따로 값을 매겨줘야 함 (D[t][w-1]값은 index가 유효하지 않으므로)
            if(cur == 1) { //지금 자두 떨어지는 위치 1이라면
                D[t][0] = D[t-1][0] + 1; //가만히 있어도 자두 얻을 수 있다. (자두는 1번 자두나무 아래 위치가 초깃값이다.)
            }
            else { //자두 떨어지는 위치 2라면
                D[t][0] = D[t-1][0]; //가만히 있으면 자두를 얻을 수 없다.
            }

            for(int w = 1 ; w <= W ; w++) {
                if(cur == 1) { //지금 자두 떨어지는 위치 1이라면,
                    if(w%2 == 0) { //현재 w 값이 짝수라서 짝수 횟수만큼 이동하여 자두가 현재 위치 1에 있다면
                        D[t][w] = Math.max(D[t-1][w] + 1, D[t-1][w-1]);
                        //D 배열에는, 이동하지 않고 그대로 자두 하나를 얻는것과, 이동하여 자두 하나를 얻지 않는 것 중에 최댓값이 들어가게 된다.
                    }
                    else { //현재 w가 홀수라서 내 위치가 2라서 떨어지는 자두와 위치가 일치하지 않는다면
                        D[t][w] = Math.max(D[t-1][w-1] + 1, D[t-1][w]);
                        //이동하여 자두를 하나 얻는것과, 이동하지 않고 자두를 얻지 않는것 중 최댓값
                    }
                }
                else { //현재 자두가 떨어지는 위치가 2라면
                    if(w%2 == 0) {
                        D[t][w] = Math.max(D[t-1][w-1] + 1, D[t-1][w]);
                    }
                    else {
                        D[t][w] = Math.max(D[t-1][w] + 1, D[t-1][w-1]);
                    }
                }
            }
        }

        int answer = 0;
        for(int i = 0 ; i <= W ; i++) {
            answer = Math.max(D[T][i], answer);
        }

        bw.write(String.valueOf(answer));
        bw.flush();
        bw.close();
        
    }

}

코드마다 자세하게 주석을 달아놓아서, 잘 읽으면 이해할 수 있다.

D 라는 배열을 채울 때,
w가 0일때와 0이 아닐 때 채우는 로직이 각각 다르다.

D[t][w] = t미터에서 w횟수만큼 이동했을 때 얻을 수 있는 자두의 최댓값
이라고 지정했기 때문에,

w의 최솟값은 0이고 그보다 더 작아질 수 없다.

그렇기에 0일때 0이 아닐때의 로직이 다른 것이다.



하나 더 설명해야 할 핵심 로직은, 아래와 같다.

아래 내용은, cur == 1일때, 즉 현재 자두가 떨어지는 위치가 1일때이다.

if(w%2 == 0) { //현재 w 값이 짝수라서 짝수 횟수만큼 이동하여 자두가 현재 위치 1에 있다면
		D[t][w] = Math.max(D[t-1][w] + 1, D[t-1][w-1]);
        //D 배열에는, 이동하지 않고 그대로 자두 하나를 얻는것과, 이동하여 자두 하나를 얻지 않는 것 중에 최댓값이 들어가게 된다.
}
else { //현재 w가 홀수라서 내 위치가 2라서 떨어지는 자두와 위치가 일치하지 않는다면
    	D[t][w] = Math.max(D[t-1][w-1] + 1, D[t-1][w]);
        //이동하여 자두를 하나 얻는것과, 이동하지 않고 자두를 얻지 않는것 중 최댓값
}

이 문제를 풀기 위해서 알아야 할 내용은,
자두는 1초보다 훨씬 짧은 시간에 움직일 수 있다는 것이다.

즉, 시작하자마자 가장 처음 자두가 떨어지는 1초도 도달하기 전에
주어진 W 횟수만큼 전부 이동할 수 있고,
해당 내용은 매 초마다 반복되어
for 문의 t값 하나하나 따라, w값 0부터 W까지 실행해야 한다.

profile
반갑습니다~! 좋은하루 보내세요 :)

0개의 댓글