๊ธ€ ์ž‘์„ฑ์ž: ๊ฐœ๋ฐœํ•˜๋Š” ํ›ˆ์ด

๋ฌธ์ œ

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
}