πŸ‘Ύ
Algorithm
기초 κ°œλ…GitHubBeakjoon
  • μ•Œκ³ λ¦¬μ¦˜ κ°œλ…
    • Dynamic Programming
    • μˆ˜ν•™ 곡식
    • κ·Έλž˜ν”„ 탐색
    • Sorting
    • 탐색 μ•Œκ³ λ¦¬μ¦˜
  • Beakjoon
    • κ·Έλž˜ν”„ 탐색
      • πŸ₯‡[κ·Έλž˜ν”„] Gold
      • πŸ₯ˆ[κ·Έλž˜ν”„] Silver
    • 완전탐색
      • πŸ₯‰[μ™„μ „ 탐색] Bronze
      • πŸ₯ˆ[μ™„μ „ 탐색] Silver
    • Dynamic Programming
      • πŸ₯ˆ[DP] Silver
    • Presum (λˆ„μ ν•©)
      • 🍼[λˆ„μ  ν•©] Silver
    • λ‹¨κ³„λ³„λ‘œ ν’€κΈ°
      • [1단계] μž…μΆœλ ₯κ³Ό 사칙연산
  • Programmers
  • 이것이 μ½”λ”©ν…ŒμŠ€νŠΈλ‹€
  • README
Powered by GitBook
On this page
  • 1463 1둜 λ§Œλ“€κΈ°
  • 2839 섀탕배달
  • 9095 1, 2, 3 λ”ν•˜κΈ°
  • 11053 κ°€μž₯ κΈ΄ μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄
  1. Beakjoon
  2. Dynamic Programming

[DP] Silver

dynamic programming

PreviousDynamic ProgrammingNextPresum (λˆ„μ ν•©)

Last updated 2 years ago

1463 1둜 λ§Œλ“€κΈ°

문제 μš”μ•½

μ •μˆ˜ x에 λŒ€ν•΄ μ„Έ κ°€μ§€ 연산을 ν•  수 μžˆλ‹€. 연산을 λ°˜λ³΅ν•˜λ©° xλ₯Ό 1둜 λ§Œλ“€κ³ μž ν•  λ•Œ, μ΅œμ†Œν•œμ˜ μ—°μ‚° 횟수λ₯Ό ꡬ해라.

  • 3으둜 λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§„λ‹€λ©΄, 3으둜 λ‚˜λˆˆλ‹€.

  • 2둜 λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§„λ‹€λ©΄, 2둜 λ‚˜λˆˆλ‹€

  • 1을 λΊ€λ‹€.

μ•Œκ³ λ¦¬μ¦˜

점화식은 λ‹€μŒκ³Ό κ°™λ‹€.F(n)=min(F(n/3),F(n/2),F(1))+1F(n) = min(F(n/3), F(n/2), F(1)) + 1F(n)=min(F(n/3),F(n/2),F(1))+1

ν•΄λ‹Ή 점화식을 μ‚¬μš©ν•˜μ—¬ Bottom up λ°©μ‹μœΌλ‘œ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€.

μ ‘κ·Ό 방법

  • κ·Έλ¦¬λ””λŠ” μ™œ μ•ˆ 될까?

  • 무쑰건 λ‚˜λˆ—μ…ˆμ΄ μˆ«μžκ°€ 더 빨리 쀄어듀기 λ•Œλ¬Έμ— 그리디λ₯Ό 생각할 수 μžˆμ§€λ§Œ, μ΅œμ νšŒκ°€ μ•„λ‹ˆλ‹€.

    • 그리디 μ•Œκ³ λ¦¬μ¦˜μ€ 3으둜 λ‚˜λˆ” -> 2둜 λ‚˜λˆ” -> 1둜 뺌의 μˆœμ„œλ‘œ 이루어 질 것이닀.

    • 2n + 1을 μƒκ°ν•΄λ³΄μž.

      • Greedy: 11 -> 10 -> 5 -> 4 -> 2 -> 1 (6회)

      • μ΅œμ ν•΄ : 11 -> 10 -> 9 -> 3 -> 1 (5회)

    • κ°„λ‹¨ν•œ μ˜ˆμ œλ‘œλ„ 그리디가 μ΅œμ ν•΄κ°€ μ•„λ‹˜μ„ 밝힐 수 μžˆλ‹€.

μ½”λ“œ

var dp = [0, 0, 1, 1]
print(makeNumberOne(Int(readLine()!)!))

func makeNumberOne(_ n: Int) -> Int {
    guard n > 3 else { return dp[n] }
    
    for i in 4 ... n {
        dp.append(dp[i-1] + 1)
        
        if i % 3 == 0 { // 3으둜 λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§„λ‹€λ©΄
            dp[i] = min(dp[i], dp[i/3] + 1)
        }
        if i % 2 == 0 { // 2둜 λ‚˜λˆ„μ–΄ λ–¨μ–΄μ§„λ‹€λ©΄
            dp[i] = min(dp[i], dp[i/2] + 1)
        }
    }
    return dp[n]
}

μ‹œκ°„μ΄ˆκ³Ό λ°œμƒ ( filter, sorted μ‚¬μš©)
var dp = [0, 0, 1, 1]
print(makeNumberOne(Int(readLine()!)!))

func makeNumberOne(_ n: Int) -> Int {
    guard n > 3 else { return dp[n] }
    
    for i in 4...n {
        var nexts = [Int](repeating: -1, count: 3)
        
        if i % 3 == 0 { nexts[0] = dp[i/3] }
        if i % 2 == 0 { nexts[1] = dp[i/2] }
        nexts[2] = dp[i-1]
        
        nexts = nexts.filter { $0 != -1 }
        
        dp.append(nexts.min()! + 1)
    }
    return dp[n]
}

2839 섀탕배달

문제 μš”μ•½

μƒκ·Όμ΄λŠ” μ •ν™•νžˆ Nkg의 섀탕을 λ°°λ‹¬ν•΄μ•Όν•œλ‹€. 섀탕은 3kg, 5kg의 봉지에 λ‹΄κ²¨μžˆλ‹€. μ΄λ•Œ 상근이가 Nkg의 섀탕을 μ΅œμ†Œν•œμ˜ λ΄‰μ§€λ‘œ λ°°λ‹¬ν•˜λ €κ³  ν•œλ‹€. μ΄λ•Œ μ΅œμ†Œ 봉지 수λ₯Ό 계산해라. (μ •ν™•νžˆ Nkg으둜 배달할 수 없을 λ•Œμ—λŠ” -1λ₯Ό 좜λ ₯ν•œλ‹€.)

μ•Œκ³ λ¦¬μ¦˜

  1. 섀탕 DP 배열을 μ„ μ–Έν•œλ‹€.

  2. 점화식 F(n)=min(F(nβˆ’3),F(nβˆ’5))+1F(n) = min(F(n-3), F(n-5)) +1F(n)=min(F(nβˆ’3),F(nβˆ’5))+1을 λ§Œμ‘±ν•˜λŠ” F(n)을 κ³„μ‚°ν•˜μ—¬ 좜λ ₯ν•œλ‹€.

접근방법

  • κ·Έλ¦¬λ””λ‘œ μ•ˆ λ˜λŠ” 이유?

    • μ²˜μŒμ—λŠ” κ·Έλ¦¬λ””λ‘œ μΆ©λΆ„νžˆ μ ‘κ·Ό κ°€λŠ₯ν•˜λ‹€κ³  μƒκ°ν–ˆλ‹€.

    • κ±°μŠ€λ¦„λˆ 문제처럼, 5ν‚€λ‘œ 그램 λ΄‰μ§€λ‘œ λ‚˜λˆ„κ³ , λ‚˜λ¨Έμ§€λ₯Ό 3ν‚€λ‘œ 봉지에 λ‹΄μœΌλ©΄ λ˜μ§€ μ•Šλ‚˜? 라고 μƒκ°ν–ˆμ§€λ§Œ μ•„λ‹ˆλ‹€!

    • 그리디 μ ‘κ·Ό 방식에 λ”°λ₯΄λ©΄, κ°€λŠ₯ν•œ 만큼 5kg둜 κ°€μ Έκ°€κ³ , λ‚˜λ¨Έμ§€λ₯Ό 3kg에 λ‹΄μ•„μ•Όν•œλ‹€.

    • ν•˜μ§€λ§Œ 5λŠ” 3의 λ°°μˆ˜κ°€ μ•„λ‹ˆλ‹€. 이에 5λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ©΄ 배달할 수 μžˆμ§€λ§Œ, 그리디 μ ‘κ·Ό λ°©λ²•μœΌλ‘œ 인해 -1이 좜λ ₯λ˜λŠ” κ²½μš°κ°€ 생긴닀.

      • μ˜ˆμ‹œ 1) 섀탕 21kg

        • Greedy : 5kg 4개, 남은 섀탕 1kg -> 배달 λΆˆκ°€, -1 좜λ ₯

        • μ‹€μ œ μ •λ‹΅ : 3kg 7개 -> 배달 κ°€λŠ₯, 7 좜λ ₯

      • μ˜ˆμ‹œ 2) 섀탕 11kg

        • Greedy: 5kg 1개, 남은 섀탕 1kg -> 배달 λΆˆκ°€, -1 좜λ ₯

        • μ‹€μ œ μ •λ‹΅: 5kg 1개, 3kg 2개 -> 배달 κ°€λŠ₯, 3 좜λ ₯

    • λ”°λΌμ„œ 이 λ¬Έμ œλŠ” κ·Έλ¦¬λ””λ‘œ ν’€ 수 μ—†λ‹€.

  • 점화식 μ„Έμš°λŠ” 방법

    • 섀탕 11kg으둜 μƒκ°ν•˜λ©΄ μ΄λ ‡κ²Œ 생각할 수 μžˆλ‹€.

      • 섀탕 6kg + 5kg = 11kg

      • 섀탕 8kg + 3kg = 11kg

    • 섀탕 8kg을 λ§Œλ“€ 수 μžˆλŠ”μ§€ μš°μ„  κ³ λ €ν•˜μ§€ μ•Šκ³ , 11kgλ₯Ό λ§Œλ“€ 수 μžˆλŠ” 경우의 수λ₯Ό μƒκ°ν•˜λ©΄ λœλ‹€. (3kg둜 λ§Œλ“€μ§€ 5kg으둜 λ§Œλ“€μ§€)

    • 그리고 섀탕 6kg으둜 λ§Œλ“œλŠ”κ²Œ 더 λΉ λ₯Έμ§€, 8kg을 λ§Œλ“œλŠ”κ²Œ 더 λΉ λ₯Έμ§€ λΉ„κ΅ν•˜λŠ” 것이닀. 이후 섀탕 봉지 5kg λ˜λŠ” 3kg을 λ”ν•˜λ©΄ λœλ‹€. (+1이 λ“€μ–΄κ°€λŠ” 이유)

    • κ·Έλž˜μ„œ 이 점화식이 λ‚˜μ˜€λŠ” 것이닀. F(n)=min(F(nβˆ’3),F(nβˆ’5))+1F(n) = min(F(n-3), F(n-5)) +1F(n)=min(F(nβˆ’3),F(nβˆ’5))+1

      • F(11) = μ΅œμ†Œ(섀탕 8kg 경우의 수, 섀탕 6kg 경우의 수) + 1

      • μ—¬κΈ°μ„œ μ£Όμ˜ν•  점은 F(x)κ°€ -1인 κ²½μš°λŠ” μœ νš¨ν•˜μ§€ μ•Šμ€ κ°’μž„μ„ μΈμ§€ν•˜κ³  μžˆμ–΄μ•Όν•œλ‹€.

μ½”λ“œ

// 섀탕 λ°°μ—΄ μ„€μ •
var sugarDP = [-1, -1, -1, 1, -1, 1]
var sugar = Int(readLine()!)!
print(getSugar(sugar))

func getSugar(_ n: Int) -> Int {
    // n이 5일 λ•Œ κΉŒμ§€λŠ” μ„ μ–Έλœ 섀탕 배열을 좜λ ₯ν•œλ‹€.
    guard n > 5 else { return sugarDP[n] }
    
    // Bottom UP λ°©μ‹μ˜ DP
    for i in 6...n {
        let prev1 = sugarDP[i-3]
        let prev2 = sugarDP[i-5]
        
        // -1은 μœ νš¨ν•˜μ§€ μ•Šμ€ κ°’μ΄λ―€λ‘œ 제거 ν›„ μ •λ ¬ν•œλ‹€.
        let temp = [prev1, prev2].filter { $0 != -1 }.sorted()
        
        // prev1κ³Ό prev2κ°€ λͺ¨λ‘ -1μ΄μ—ˆλ‹€λ©΄, -1을 μΆ”κ°€ν•œλ‹€.
        guard !temp.isEmpty else {
            sugarDP.append(-1)
            continue
        }
        
        // prev1, prev2 쀑 μž‘μ€ 값에 1을 더해 iλ₯Ό κ³„μ‚°ν•œλ‹€.
        sugarDP.append(temp[0] + 1)
    }
    return sugarDP[n]
}
그리디 μ ‘κ·Ό 방식 (ν‹€λ¦° 방법)
var sugar = Int(readLine()!)!
var result = 0

for x in [3, 5] {
    if sugar >= x {
        result += sugar / x
        sugar %= x
    }
}
print( sugar == 0 ? result : -1)

9095 1, 2, 3 λ”ν•˜κΈ°

문제 μš”μ•½

μ •μˆ˜ n이 μ£Όμ–΄μ‘Œμ„ λ•Œ, 1, 2, 3의 ν•©μœΌλ‘œ λ‚˜νƒ€λ‚Ό 수 μžˆλŠ” 경우의 수λ₯Ό 계산해라.

n = 3이라면 (1+1+1, 1+2, 2+1, 3) 4κ°€μ§€λ‘œ ν‘œν˜„ν•  수 μžˆλ‹€.

접근방법

  • 사싀 κ·œμΉ™μ„ μƒκ°ν•˜κΈ° 전에 점화식이 λ– μ˜¬λžλ‹€. (μ–»μ–΄ κ±Έλ Έλ‹€λŠ” 말)

  • 점화식 F(n)=F(nβˆ’1)+F(nβˆ’2)+F(nβˆ’3)F(n) = F(n-1) + F(n-2) + F(n-3)F(n)=F(nβˆ’1)+F(nβˆ’2)+F(nβˆ’3)

    • 이게 μ™œ λ§žμ§€? λΌλŠ” 생각을 ν–ˆλŠ”λ° F(1)의 1이 μ˜λ―Έν•˜λŠ” λ°”κ°€ μ΅œλŒ“κ°’μ΄ 1이라고 μƒκ°ν•˜λ©΄ μ‰½κ²Œ 이해할 수 μžˆλ‹€.

    • F(4) = F(3) + F(2) + F(1) 이닀.

      • F(1)μ—μ„œ 3을 λ”ν•˜λ©΄ 4, F(2)μ—μ„œ 2λ₯Ό λ”ν•˜λ©΄ 4, F(3)μ—μ„œ 1을 λ”ν•˜λ©΄ 4κ°€ λœλ‹€.

    • λ§ˆμ°¬κ°€μ§€λ‘œ F(7) = F(6) + F(5) + F(4)

      • F(6)μ—μ„œ 1을 λ”ν•˜λ©΄ 7, F(5)μ—μ„œ 2λ₯Ό λ”ν•˜λ©΄, F(4)μ—μ„œ 3을 λ”ν•˜λ©΄ 7이 λœλ‹€.

  • 경우의 μˆ˜μ™€ 연산을 ν—·κ°ˆλ¦¬μ§€ 말자!!

μ½”λ“œ

var dp = [0, 1, 2, 4]

// 점화식을 μ½”λ“œλ‘œ ν‘œν˜„ν•œλ‹€.
for i in 4...11 {
    dp.append(dp[i-1] + dp[i-2] + dp[i-3])
}

// κ²°κ³Όλ₯Ό 좜λ ₯ν•œλ‹€.
let testCase = Int(readLine()!)!
for _ in 0 ..< testCase {
    print(dp[Int(readLine()!)!])
}

11053 κ°€μž₯ κΈ΄ μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄

문제 μš”μ•½

μˆ˜μ—΄ Aκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ, κ°€μž₯ κΈ΄ μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄μ„ κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•΄λΌ.

μ•Œκ³ λ¦¬μ¦˜

  1. μˆ˜μ—΄μ„ μž…λ ₯λ°›λŠ”λ‹€.

  2. λ‚˜λ³΄λ‹€ μž‘μ€ 수 쀑 λΆ€λΆ„ μˆ˜μ—΄μ΄ κ°€μž₯ κΈ΄ 값을 μ°Ύμ•„ μ €μž₯ν•œλ‹€.

  3. result의 μ΅œλŒ“κ°’μ„ 좜λ ₯ν•œλ‹€.

μ ‘κ·Ό 방법

  • μš°μ„  κ°€μž₯ κΈ΄ μ¦κ°€ν•˜λŠ” λΆ€λΆ„μˆ˜μ—΄μ΄λΌλŠ” 말 λΆ€ν„° 이해λ₯Ό ν•΄ 보자.

    • λΆ€λΆ„ μˆ˜μ—΄ = "μ£Όμ–΄μ§„ μˆ˜μ—΄μ˜ 일뢀 항을 μ›λž˜ μˆœμ„œλŒ€λ‘œ λ‚˜μ—΄ν•˜μ—¬ 얻을 수 μžˆλŠ” μˆ˜μ—΄"

    • μ¦κ°€ν•˜λŠ” μˆ˜μ—΄ = "μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ¦κ°€ν•˜λŠ” μˆ˜μ—΄"

    • κ°€μž₯ κΈ΄ μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄ = μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ •λ ¬λ˜λŠ” λΆ€λΆ„μˆ˜μ—΄ 쀑 lengthκ°€ κ°€μž₯ κΈ΄ μˆ˜μ—΄

      -> [10, 20, 10, 30, 20, 50]μ—μ„œ κ°€μž₯ κΈ΄ μ¦κ°€ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄ = [10, 20, 30, 50]이 λ˜λŠ” 것이닀.

  • 문제λ₯Ό μ΄ν•΄ν–ˆμœΌλ‹ˆ, 문제λ₯Ό ν‘ΈλŠ” 방법을 곰곰히 μƒκ°ν•΄λ³΄μž!

    • μš°μ„ , μ›μ†Œ x에 λŒ€ν•΄ μ΅œμ†Œ λΆ€λΆ„ μˆ˜μ—΄μ˜ κΈΈμ΄λŠ” 뭘까? -> 1이닀! (x둜만 이루어진 λΆ€λΆ„ μˆ˜μ—΄μ΄ 있기 λ•Œλ¬Έ)

    • 그럼 xλ₯Ό ν¬ν•¨ν•˜λŠ” λΆ€λΆ„ μˆ˜μ—΄μ„ κ΅¬ν•˜λŠ” 방법은 뭘까?

      • 자기 μžμ‹ λ³΄λ‹€ μž‘μ€ 수 쀑 result[n]이 κ°€μž₯ 큰 것 + 1 이 λœλ‹€.

      • 즉, max( result[1...x-1] + 1, 단 x보닀 μž‘μ€ 경우)

  • λ„ˆλ¬΄ μΆ”μƒμ μ΄λ‹ˆ [10, 20, 10, 30, 20, 50]으둜 λ‹€μ‹œ μƒκ°ν•΄λ³΄μž.

    • result λ°°μ—΄μ—λŠ” [1, 1, 1, 1, 1, 1] 이 μ €μž₯ 돼 μžˆλ‹€.

    • (10은 비ꡐ할 게 μ—†μœΌλ‹ˆ λ„˜μ–΄κ°„λ‹€.) 20은 10보닀 크닀. λ”°λΌμ„œ 10의 resultμ—μ„œ 1을 λ”ν•œ 값을 κ°–λŠ”λ‹€.

    • λ‹€μŒ 3번째 μ›μ†Œ 10을 λ³΄λ‹ˆ, 10보닀 μž‘μ€ 값이 μ „ν˜€ μ—†μœΌλ―€λ‘œ κ·ΈλŒ€λ‘œ result λŠ” 1이닀.

    • λ‹€μŒ 4번째 μ›μ†Œ 30을 보자. [10, 20, 10]은 λͺ¨λ‘ 30보닀 μž‘λ‹€. 이 쀑 resultκ°€ κ°€μž₯ 큰 것은 20이닀. λ”°λΌμ„œ 30에 λŒ€ν•œ result 값은 2 + 1 = 3이 λœλ‹€. (2: 20을 ν¬ν•¨ν–ˆμ„ λ•Œ λΆ€λΆ„ μˆ˜μ—΄, 1은 30이 ν¬ν•¨λ˜λŠ” 숫자)

    • λ‹€μŒ 20을 보자. μžκΈ°λ³΄λ‹€ μž‘μ€ [10, 10] 에 λŒ€ν•΄ λΆ€λΆ„μˆ˜μ—΄μ„ λ§Œλ“€ 수 있고, 1+1 = 2κ°€ λœλ‹€.

    • λ§ˆμ§€λ§‰ 50을 보자. μžκΈ°λ³΄λ‹€ μž‘μ€ λͺ¨λ“  값에 λŒ€ν•΄ μ‘°νšŒν•˜κ³ , κ°€μž₯ 큰 3 + 1 = 4κ°€ λœλ‹€.

let n = Int(readLine()!)!
let numbers = readLine()!.split { $0 == " " }.map { Int($0)! }
var result = [Int](repeating: 1, count: n)

for i in 0 ..< n {
    var count = 1
    for j in stride(from: i, to: -1, by: -1) {
        if numbers[i] > numbers[j] {
            count = max(count, result[j] + 1)
        }
    }
    result[i] = count
}

print(result.max()!)

πŸ₯ˆ
문제둜 이동
문제둜 이동
문제둜 이동
문제둜 이동