Programming/Kotlin

[백준/Kotlin] 자두나무(2240)

코딩뽀시래기 2024. 5. 14. 22:11
728x90

문제

자두는 자두를 좋아한다. 그래서 집에 자두나무를 심어두고, 여기서 열리는 자두를 먹고는 한다. 하지만 자두는 키가 작아서 자두를 따먹지는 못하고, 자두가 떨어질 때까지 기다린 다음에 떨어지는 자두를 받아서 먹고는 한다. 자두를 잡을 때에는 자두가 허공에 있을 때 잡아야 하는데, 이는 자두가 말랑말랑하여 바닥에 떨어지면 못 먹을 정도로 뭉개지기 때문이다.

매 초마다, 두 개의 나무 중 하나의 나무에서 열매가 떨어지게 된다. 만약 열매가 떨어지는 순간, 자두가 그 나무의 아래에 서 있으면 자두는 그 열매를 받아먹을 수 있다. 두 개의 나무는 그다지 멀리 떨어져 있지 않기 때문에, 자두는 하나의 나무 아래에 서 있다가 다른 나무 아래로 빠르게(1초보다 훨씬 짧은 시간에) 움직일 수 있다. 하지만 자두는 체력이 그다지 좋지 못해서 많이 움직일 수는 없다.

자두는 T(1≤T≤1,000)초 동안 떨어지게 된다. 자두는 최대 W(1≤W≤30)번만 움직이고 싶어 한다. 매 초마다 어느 나무에서 자두가 떨어질지에 대한 정보가 주어졌을 때, 자두가 받을 수 있는 자두의 개수를 구해내는 프로그램을 작성하시오. 자두는 1번 자두나무 아래에 위치해 있다고 한다.

 

[ 입력 ]

첫째 줄에 두 정수 T, W가 주어진다. 다음 T개의 줄에는 각 순간에 자두가 떨어지는 나무의 번호가 1 또는 2로 주어진다.

 

[ 출력 ]

첫째 줄에 자두가 받을 수 있는 자두의 최대 개수를 출력한다.

 


풀이

- 처음에는 떨어지는 나무가 변하는 시간을 체크해서, 바뀌는 시점 중에 W개 이하를 선택하고 받을 수 있는 자두의 개수를 계산했는데 시간 초과가 나왔다.

- 그래서 고민하다가 java 풀이 솔루션을 찾아보니 dp를 사용하는 문제라는 걸 알 수 있었다.

- 찾아본 솔루션에서 1번 나무일 때, 2번 나무일 때마다 if문을 쓰고 있길래 이 부분을 if문 없이 바꿔보았다. 

// 백준 - 자두나무(2240)
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.StringTokenizer
import kotlin.math.max

fun main() {
  val br = BufferedReader(InputStreamReader(System.`in`))
  var st = StringTokenizer(br.readLine())

  val T = st.nextToken().toInt() // 떨어지는 자두의 개수
  val W = st.nextToken().toInt() // 자두가 최대로 움직일 횟수

  val plum: Array<Int> = Array(T + 1, {0})
  // [시간][이동 횟수][현재 위치]
  val dp: Array<Array<Array<Int>>> = Array(T + 1, {Array(W + 1, {Array(3, {0})})})
  
  for(i: Int in 1..T) {
    plum[i] = br.readLine().toInt()
  }

  // 첫번째 자두가 1번 나무에서 떨어질 경우 초기값
  if(plum[1] == 1) {
    dp[1][0][1] = 1 // 위치 유지, 자두 1개
    dp[1][1][2] = 0 // 위치 이동, 자두 0개
  }
  // 첫번째 자두가 2번 나무에서 떨어질 경우 초기값
  else {
    dp[1][0][1] = 0 // 위치 유지, 자두 0개
    dp[1][1][2] = 1 // 위치 이동, 자두 1개
  }

  for(t: Int in 2..T) {
    // 1번에서 받을 수 있는 자두 => 1이면 1, 2이면 0으로
    var one = plum[t] % 2
    // 2번에서 받을 수 있는 자두 => 1이면 0, 2이면 1으로
    var two = (plum[t] + 1) % 2

    // 이동 횟수 0
    dp[t][0][1] = dp[t - 1][0][1] + one
    dp[t][0][2] = dp[t - 1][0][2] + two

    // 이동 횟수 1 이상
    for(w: Int in 1..W) {
      // 이전에 이동을 w번 했거나, w-1 했었는데 지금 이동 추가 중 더 자두를 많이 받은 경우
      dp[t][w][1] = max(dp[t-1][w][1], dp[t-1][w-1][2]) + one
      dp[t][w][2] = max(dp[t-1][w][2], dp[t-1][w-1][1]) + two
    }
  }

  // 최대값
  var maxPlum = 0
  for(w: Int in 0..W) {
    maxPlum = max(maxPlum, max(dp[T][w][1], dp[T][w][2]))
  }

  print(maxPlum)
}
728x90

'Programming > Kotlin' 카테고리의 다른 글

[백준/Kotlin] 공유기 설치(2110)  (0) 2024.05.15
[백준/Kotlin] 내려가기(2096)  (0) 2024.05.15
[백준/Kotlin] 다이어트(1484)  (0) 2024.05.14
[백준/Kotlin] 연구소 3(17142)  (0) 2024.05.10
[백준/Kotlin] 물병(1052)  (0) 2024.05.10