Algorithm/BOJ

백준 16236 아기상어

삼쓰 웅쓰 2021. 3. 10. 18:08
728x90

출처: www.acmicpc.net/problem/16236

분류: BFS


접근방식

상어가 먹이를 찾을 수 없을 때가지 최단거리의 먹이를 찾아 bfs를 돌려주면 되는 문제였습니다.

기술적으로 크게 어려운 것은 없었으나... 익숙하지 않다면 구현에서 좀 애를 먹을 수 있을 것 같네요..! (후 힘들었습니다..)

같은 거리의 먹이들이 여러 개라면 요구사항대로 정렬을 해줘야 합니다! row 우선, 그다음 col로 ..!

feeds.sorted(by: { $0.r == $1.r ? $0.c < $1.c : $0.r < $1.r})


큐에서 DoubleStackQueue를 사용했는데 그냥 배열로 해서 removeFirst해도 통과가 가능한 것 같습니다.

 

해결방법

struct DoubleStackQueue<Element> {
    private var inbox: [Element] = []
    private var outbox: [Element] = []
    
    var isEmpty: Bool{
        return inbox.isEmpty && outbox.isEmpty
    }
    
    var count: Int{
        return inbox.count + outbox.count
    }
    
    var front: Element? {
        return outbox.last ?? inbox.first
    }
    
    init() { }
    
    init(_ array: [Element]) {
        self.init()
        self.inbox = array
    }
    
    mutating func enqueue(_ n: Element) {
        inbox.append(n)
    }
    
    mutating func dequeue() -> Element {
        if outbox.isEmpty {
            outbox = inbox.reversed()
            inbox.removeAll()
        }
        return outbox.removeLast()
    }
}

extension DoubleStackQueue: ExpressibleByArrayLiteral {
    init(arrayLiteral elements: Element...) {
        self.init()
        inbox = elements
    }
}

let n = Int(readLine()!)!
var map = [[Int]]()
typealias Point = (r: Int, c: Int)
var start: Point!

for r in 0..<n {
    map.append(readLine()!.split(separator: " ").map { Int(String($0))! })
    if let baby = map[r].enumerated().filter({ $0.element == 9 }).first {
        start = (r, baby.offset)
        map[r][baby.offset] = 0
    }
}

func nexts(_ p: Point) -> [Point] {
    return [
        Point(p.r-1, p.c),
        Point(p.r, p.c-1),
        Point(p.r, p.c+1),
        Point(p.r+1, p.c),
    ]
}

func isInRange(_ p: Point) -> Bool {
    return 0..<n ~= p.r && 0..<n ~= p.c
}

func nearbyFeed(_ start: Point) -> (Int, Point)? {
    var dist = [[Int]](repeating: [Int](repeating: 0, count: n), count: n)
    dist[start.r][start.c] = 0
    var q = DoubleStackQueue<Point>()
    q.enqueue(start)
    var nearst = -1
    var feeds = [Point]()
    
    while !q.isEmpty {
        let curr = q.dequeue()
        for next in nexts(curr) where isInRange(next) && next != start {
            if dist[next.r][next.c] == 0, map[next.r][next.c] <= shark {
                q.enqueue(next)
                dist[next.r][next.c] = dist[curr.r][curr.c] + 1
                if map[next.r][next.c] != 0, map[next.r][next.c] < shark {
                    if dist[next.r][next.c] < nearst || nearst == -1 {
                        nearst = dist[next.r][next.c]
                        feeds = [next]
                    } else if nearst == dist[next.r][next.c] {
                        feeds.append(next)
                    }
                }
            }
        }
    }
    
    let nearstPoint = feeds.sorted(by: { $0.r == $1.r ? $0.c < $1.c : $0.r < $1.r}).first
    return (nearstPoint == nil || nearst == -1) ? nil : (nearst, nearstPoint!)
}

var shark = 2
var feeds = 0
var moving = 0

while let (dist, next) = nearbyFeed(start) {
    start = next
    moving += dist
    map[next.r][next.c] = 0
    feeds += 1
    if shark == feeds {
        feeds = 0
        shark += 1
    }
}

print(moving)

 

 

배운점

연습!! 노오오오오오오력으로 간다