πŸ’†πŸ»‍♂️ ν”Ό-μ—μŠ€/🐣 ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

[μŠ€μœ„ν”„νŠΈ μ•Œκ³ λ¦¬μ¦˜] ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€: 배달

κ°œλ°œν•˜λŠ” ν›ˆμ΄ 2021. 7. 25. 17:31

문제

N개의 λ§ˆμ„λ‘œ 이루어진 λ‚˜λΌκ°€ μžˆμŠ΅λ‹ˆλ‹€. 이 λ‚˜λΌμ˜ 각 λ§ˆμ„μ—λŠ” 1λΆ€ν„° NκΉŒμ§€μ˜ λ²ˆν˜Έκ°€ 각각 ν•˜λ‚˜μ”© λΆ€μ—¬λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 각 λ§ˆμ„μ€ μ–‘λ°©ν–₯으둜 톡행할 수 μžˆλŠ” λ„λ‘œλ‘œ μ—°κ²°λ˜μ–΄ μžˆλŠ”λ°, μ„œλ‘œ λ‹€λ₯Έ λ§ˆμ„ 간에 이동할 λ•ŒλŠ” 이 λ„λ‘œλ₯Ό μ§€λ‚˜μ•Ό ν•©λ‹ˆλ‹€. λ„λ‘œλ₯Ό 지날 λ•Œ κ±Έλ¦¬λŠ” μ‹œκ°„μ€ λ„λ‘œλ³„λ‘œ λ‹€λ¦…λ‹ˆλ‹€. ν˜„μž¬ 1번 λ§ˆμ„μ— μžˆλŠ” μŒμ‹μ μ—μ„œ 각 λ§ˆμ„λ‘œ μŒμ‹ 배달을 ν•˜λ €κ³  ν•©λ‹ˆλ‹€. 각 λ§ˆμ„λ‘œλΆ€ν„° μŒμ‹ 주문을 λ°›μœΌλ €κ³  ν•˜λŠ”λ°, N개의 λ§ˆμ„ μ€‘μ—μ„œ K μ‹œκ°„ μ΄ν•˜λ‘œ 배달이 κ°€λŠ₯ν•œ λ§ˆμ„μ—μ„œλ§Œ 주문을 λ°›μœΌλ €κ³  ν•©λ‹ˆλ‹€. λ‹€μŒμ€ N = 5, K = 3인 경우의 μ˜ˆμ‹œμž…λ‹ˆλ‹€.

μœ„ κ·Έλ¦Όμ—μ„œ 1번 λ§ˆμ„μ— μžˆλŠ” μŒμ‹μ μ€ [1, 2, 4, 5] 번 λ§ˆμ„κΉŒμ§€λŠ” 3 μ΄ν•˜μ˜ μ‹œκ°„μ— 배달할 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 3번 λ§ˆμ„κΉŒμ§€λŠ” 3μ‹œκ°„ μ΄λ‚΄λ‘œ 배달할 수 μžˆλŠ” κ²½λ‘œκ°€ μ—†μœΌλ―€λ‘œ 3번 λ§ˆμ„μ—μ„œλŠ” 주문을 받지 μ•ŠμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 1번 λ§ˆμ„μ— μžˆλŠ” μŒμ‹μ μ΄ 배달 주문을 받을 수 μžˆλŠ” λ§ˆμ„μ€ 4κ°œκ°€ λ©λ‹ˆλ‹€.
λ§ˆμ„μ˜ 개수 N, 각 λ§ˆμ„μ„ μ—°κ²°ν•˜λŠ” λ„λ‘œμ˜ 정보 road, μŒμ‹ 배달이 κ°€λŠ₯ν•œ μ‹œκ°„ Kκ°€ λ§€κ°œλ³€μˆ˜λ‘œ μ£Όμ–΄μ§ˆ λ•Œ, μŒμ‹ 주문을 받을 수 μžˆλŠ” λ§ˆμ„μ˜ 개수λ₯Ό return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μ™„μ„±ν•΄μ£Όμ„Έμš”.

μ œν•œμ‚¬ν•­

  • λ§ˆμ„μ˜ 개수 N은 1 이상 50 μ΄ν•˜μ˜ μžμ—°μˆ˜μž…λ‹ˆλ‹€.
  • road의 길이(λ„λ‘œ μ •λ³΄μ˜ 개수)λŠ” 1 이상 2,000 μ΄ν•˜μž…λ‹ˆλ‹€.
  • road의 각 μ›μ†ŒλŠ” λ§ˆμ„μ„ μ—°κ²°ν•˜κ³  μžˆλŠ” 각 λ„λ‘œμ˜ 정보λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
  • roadλŠ” 길이가 3인 배열이며, μˆœμ„œλŒ€λ‘œ (a, b, c)λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
    • a, b(1 ≤ a, b ≤ N, a != b)λŠ” λ„λ‘œκ°€ μ—°κ²°ν•˜λŠ” 두 λ§ˆμ„μ˜ 번호이며, c(1 ≤ c ≤ 10,000, cλŠ” μžμ—°μˆ˜)λŠ” λ„λ‘œλ₯Ό μ§€λ‚˜λŠ”λ° κ±Έλ¦¬λŠ” μ‹œκ°„μž…λ‹ˆλ‹€.
    • 두 λ§ˆμ„ a, bλ₯Ό μ—°κ²°ν•˜λŠ” λ„λ‘œλŠ” μ—¬λŸ¬ κ°œκ°€ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
    • ν•œ λ„λ‘œμ˜ 정보가 μ—¬λŸ¬ 번 μ€‘λ³΅ν•΄μ„œ 주어지지 μ•ŠμŠ΅λ‹ˆλ‹€.
  • KλŠ” μŒμ‹ 배달이 κ°€λŠ₯ν•œ μ‹œκ°„μ„ λ‚˜νƒ€λ‚΄λ©°, 1 이상 500,000 μ΄ν•˜μž…λ‹ˆλ‹€.
  • μž„μ˜μ˜ 두 λ§ˆμ„κ°„μ— 항상 이동 κ°€λŠ₯ν•œ κ²½λ‘œκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.
  • 1번 λ§ˆμ„μ— μžˆλŠ” μŒμ‹μ μ΄ K μ΄ν•˜μ˜ μ‹œκ°„μ— 배달이 κ°€λŠ₯ν•œ λ§ˆμ„μ˜ 개수λ₯Ό return ν•˜λ©΄ λ©λ‹ˆλ‹€.

풀이

μ „ν˜•μ μΈ λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ μ΅œλ‹¨κ±°λ¦¬λ₯Ό μ°ΎλŠ” λ¬Έμ œμ˜€μŠ΅λ‹ˆλ‹€. C++ κ³ΌλŠ” λ‹€λ₯΄κ²Œ μŠ€μœ„ν”„νŠΈμ—μ„œλŠ” νž™κ³Ό μš°μ„ μˆœμœ„ν μžλ£Œκ΅¬μ‘°κ°€ μ—†μ–΄μ„œ 자료ꡬ쑰λ₯Ό μ™„μ „νžˆ μƒˆλ‘œ λ§Œλ“€μ–΄μ„œ μ‚¬μš©ν•˜κ±°λ‚˜, 배열에 μš”μ†Œλ“€μ„ 집어넣고 λΉΌλ‚΄κΈ° 직전에 μš°μ„ μˆœμœ„ κΈ°μ€€μœΌλ‘œ 정렬을 ν•˜κ³  μš”μ†Œλ₯Ό λΉΌλŠ” λ°©λ²•μœΌλ‘œ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 두 방법에 λŒ€ν•œ μ½”λ“œλ₯Ό λͺ¨λ‘ μ²¨λΆ€ν•©λ‹ˆλ‹€.

μ½”λ“œ

νž™κ³Ό μš°μ„ μˆœμœ„ 큐λ₯Ό μ •μ˜ν•˜μ§€ μ•Šκ³  정렬을 톡해 ν•΄κ²°ν•œ 풀이

import Foundation


func calcDists(_ distances: inout [Int], _ costs: inout [[(Int, Int)]]) {
    var pq : [(Int, Int)] = []
    pq.append((1, 0))
    distances[1] = 0
    
    while(!pq.isEmpty) {
        pq.sort(by: <)
        let (here, costHere) = pq.removeFirst()
        
        for (there, costThere) in costs[here] {
            if distances[there] > costHere + costThere {
                distances[there] = costHere + costThere
                pq.append((there, distances[there]))
            }
        }
    }
}

func solution(_ N:Int, _ road:[[Int]], _ k:Int) -> Int {
    var distances = Array(repeating: 987654321, count: N + 1)
    var costs = Array(repeating: [(Int, Int)](), count: N + 1)
    
    for info in road {
        costs[info[0]].append((info[1], info[2]))
        costs[info[1]].append((info[0], info[2]))
    }

    calcDists(&distances, &costs)
    
    return distances.filter({ $0 <= k }).count
}

 

νž™κ³Ό μš°μ„ μˆœμœ„ 큐λ₯Ό κ΅¬ν˜„ν•œ 풀이

import Foundation

struct Heap<Element> {
    var elements : [Element]
    let sort : (Element, Element) -> Bool
    
    var isEmpty : Bool {
        return elements.isEmpty
    }
    
    var count : Int {
        return elements.count
    }
    
    init(elements: [Element] = [], sort: @escaping (Element, Element) -> Bool) {
        self.elements = elements
        self.sort = sort
        buildHeap()
    }
    
    // λ§ˆμ§€λ§‰ λ¦¬ν”„λ…Έλ“œμ˜ λΆ€λͺ¨λ…Έλ“œλΆ€ν„° λ£¨νŠΈλ…Έλ“œκΉŒμ§€ diveDown을 μˆ˜ν–‰ν•œλ‹€.
    mutating func buildHeap() {
        for index in (0..<(count / 2)).reversed() {
            diveDown(from: index)
        }
    }
    
    func peek() -> Element? {
        return elements.first
    }
    
    func isRoot(_ index: Int) -> Bool {
        return index == 0
    }
    
    func leftChildIndex(of index: Int) -> Int {
        return (2 * index) + 1
    }
    
    func rightChildIndex(of index: Int) -> Int {
        return (2 * index) + 2
    }
    
    func parentIndex(of index: Int) -> Int {
        return (index - 1) / 2
    }
    
    func isWithHigherPriority (at firstIdx: Int, than secondIdx: Int) -> Bool {
        return sort(elements[firstIdx], elements[secondIdx])
    }
    
    // μ™Όμͺ½ μžλ…€λ…Έλ“œκ°€ μžˆλŠ” κ²½μš°μ—λŠ” λΆ€λͺ¨λ…Έλ“œμ™€ λΉ„κ΅ν•˜μ—¬ 더 큰 λ…Έλ“œμ˜ 인덳슀λ₯Ό λ°˜ν™˜ν•˜κ³ , μ—†λ‹€λ©΄ λΆ€λͺ¨λ…Έλ“œμ˜ 인덱슀λ₯΄ λ°˜ν™˜ν•œλ‹€.
    func higherPriorityWithChild(parentIndex: Int, childIndex: Int) -> Int {
        guard childIndex < count && isWithHigherPriority(at: childIndex, than: parentIndex) else {
            return parentIndex
        }
        return childIndex
    }
    
    // μ™Όμͺ½ μžλ…€λ…Έλ“œμ™€ λΆ€λͺ¨λ…Έλ“œ 쀑 μš°μ„ μˆœμœ„κ°€ 더 큰 λ…Έλ“œμ™€ 였λ₯Έμͺ½ μžλ…€λ…Έλ“œλ₯Ό λΉ„κ΅νžˆμ—¬ 더 큰 λ…Έλ“œμ˜ 인덱슀λ₯Ό λ°˜ν™˜ν•œλ‹€.
    func higherPriorityOfChildren(for parent: Int) -> Int {
        return higherPriorityWithChild(
            parentIndex: higherPriorityWithChild(parentIndex: parent,
                                                 childIndex: leftChildIndex(of: parent)),
            childIndex: rightChildIndex(of: parent))
    }
    
    mutating func swapElement (at firstIndex: Int, with secondIndex: Int){
        elements.swapAt(firstIndex, secondIndex)
    }
    
    // 트리의 κ°€μž₯ λ§ˆμ§€λ§‰μ— μƒˆλ‘œμš΄ λ…Έλ“œλ₯Ό μ‚½μž…ν•˜κ³  swimUp으둜 트리λ₯Ό μž¬μ‘°μ •ν•œλ‹€.
    mutating func push (_ element: Element) {
        elements.append(element)
        swimUp(fromIndex: count - 1)
    }
    
    // μ§€μ •λœ μΈλ±μŠ€λΆ€ν„° μžμ‹ μ˜ λΆ€λͺ¨λ…Έλ“œμ™€ λΉ„κ΅ν•˜λ©΄μ„œ λΆ€λͺ¨λ…Έλ“œλ³΄λ‹€ μš°μ„ μˆœμœ„κ°€ λ†’λ‹€λ©΄ 두 λ…Έλ“œλ₯Ό κ΅μ²΄ν•œ λ’€ μƒˆλ‘­κ²Œ λΆ€λͺ¨λ…Έλ“œκ°€ 된 λ…Έλ“œλΆ€ν„° swimUp을 λ‹€μ‹œ μˆ˜ν–‰ν•œλ‹€.
    mutating func swimUp(fromIndex index: Int) {
        let parentIdx = parentIndex(of: index)
        guard !isRoot(index), isWithHigherPriority(at: index, than: parentIdx) else {
            return
        }
        swapElement(at: index, with: parentIdx)
        swimUp(fromIndex: parentIdx)
    }
    
    // λ£¨νŠΈλ…Έλ“œμ˜ λ‚΄μš©μ„ λ§ˆμ§€λ§‰ λ¦¬ν”„λ…Έλ“œμ˜ λ‚΄μš©κ³Ό κ΅ν™˜ν•œλ’€ λ§ˆμ§€λ§‰ λ¦¬ν”„λ…Έλ“œλ₯Ό 떼어버린닀. 그리고 λ£¨νŠΈλ…Έλ“œλΆ€ν„° diveDown을 μˆ˜ν–‰ν•˜μ—¬ 트리λ₯Ό μž¬μ‘°μ •ν•œλ‹€.
    mutating func pop() -> Element? {
        guard !isEmpty else {
            return nil
        }
        swapElement(at: 0, with: count - 1)
        let removedElement = elements.removeLast()
        if !isEmpty {
            diveDown(from: 0)
        }
        return removedElement
    }
    
    // λΆ€λͺ¨λ…Έλ“œμ™€ μžλ…€λ…Έλ“œλ₯Ό λΉ„κ΅ν•˜λ©΄μ„œ μžλ…€λ…Έλ“œμ˜ μš°μ„ μˆœμœ„κ°€ 더 λ†’λ‹€λ©΄ κ΅ν™˜ν•œλ‹€.
    mutating func diveDown(from index: Int){
        let childIndex = higherPriorityOfChildren(for: index)
        if index == childIndex {
            return
        }
        swapElement(at: index, with: childIndex)
        diveDown(from: childIndex)
    }
}

struct PriorityQueue<T> {
    var heap: Heap<T>
    
    init(_ elements: [T], _ sort: @escaping (T, T) -> Bool) {
        heap = Heap(elements: elements, sort: sort)
    }
    
    var count : Int {
        return heap.count
    }
    
    var isEmpty : Bool {
        return heap.isEmpty
    }
    
    mutating func clear () {
        heap = Heap<T>(elements: [], sort: heap.sort)
    }
    
    func top () -> T? {
        return heap.peek()
    }
    
    mutating func pop() -> T? {
        return heap.pop()
    }
    
    mutating func push(_ element: T) {
        heap.push(element)
    }
}


func calcDists(_ distances: inout [Int], _ costs: inout [[(Int, Int)]]) {
    var pq = PriorityQueue<(Int, Int)>([], { $0.1 < $1.1 })
    pq.push((1, 0))
    distances[1] = 0
    
    while(!pq.isEmpty) {
        let (here, costHere) = pq.pop()!
        
        for (there, costThere) in costs[here] {
            if distances[there] > costHere + costThere {
                distances[there] = costHere + costThere
                pq.push((there, distances[there]))
            }
        }
    }
}

func solution(_ N:Int, _ road:[[Int]], _ k:Int) -> Int {
    var distances = Array(repeating: 987654321, count: N + 1)
    var costs = Array(repeating: [(Int, Int)](), count: N + 1)
    
    for info in road {
        costs[info[0]].append((info[1], info[2]))
        costs[info[1]].append((info[0], info[2]))
    }

    calcDists(&distances, &costs)
    
    return distances.filter({ $0 <= k }).count
}