Algorithm/BOJ

백준 1939 중량제한

삼쓰 웅쓰 2021. 3. 4. 17:06
728x90

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

분류: 이분 탐색


접근방식

하 이번 문제도 너무 어려웠습니다... 설명이 애매해서 이해도 어려웠고 메모리제한............ ㅂㄷㅂㄷ

먼저 문제의 마지막에 

" 한 번의 이동에서 옮길 수 있는 물품들의 중량의 최댓값을 구하는 프로그램을 작성하시오. "

라고 되어있어서 마지막에 주어진  두 섬으로 한 번에 가는 경우를 체크하는건가? 그럼 중간에 경로들은 왜 주어진거지? 문제가 좀 이상한데? 라고 생각했었습니다. 

결국 여기서 말하는 한 번의 이동이란 처음 섬에서 특정 중량으로 출발시킨 짐이  목표 섬까지 도착하는 경로를 의미합니다.

 

중량을 기준으로 이분 탐색을 해서 각 중량으로 이동이 가능한지 체크해서 해결했습니다.

var mostWeight = 0
while low <= high {
    let mid = (low + high)/2

    if canMove(for: mid) {
        mostWeight = mid
        low = mid+1
    } else {
        high = mid-1
    }
}

이동이 가능한지는 제한 무게보다 크거나 같은지 체크하면서 bfs를 돌렸습니다.

func canMove(for weight: Int) -> Bool {
    var visited = Set<Int>([ab[0]])
    var q: [Int] = [ab[0]]
    
    while !q.isEmpty {
        let curr = q.removeFirst()
        for (island, w) in islands[curr] where w >= weight {
            if island == ab[1] {
                return true
            }
            guard !visited.contains(island) else { continue }
            visited.insert(island)
            q.append(island)
        }
    }
    return false
}

 

마지막 난관은 메모리 제한이었는데.....

bfs에서 queue를 써야하다 보니까 시간을 의식해서 더블스택 큐를 만들어서 사용했는데, 여기서 배열을 많이 생성해서 사용핟보니 메모리 제한에 걸렸던 것 같습니다. 어차피 이분 탐색은 탐색을 그렇게 많이 하지 않기 때문에 그냥 array의 removeFirst 사용해서 통과했습니다 ㅠㅠ

 

해결방법

let nm = readLine()!.split(separator: " ").map { Int(String($0))! }
var islands = [[(Int, Int)]](repeating: [], count: nm[0]+1)

var low = 0
var high = 0

for _ in 0..<nm[1] {
    let abc = readLine()!.split(separator: " ").map { Int(String($0))! }
    islands[abc[0]].append((abc[1], abc[2]))
    islands[abc[1]].append((abc[0], abc[2]))
    high = max(high, abc[2])
}
let ab = readLine()!.split(separator: " ").map { Int(String($0))! }

var mostWeight = 0
while low <= high {
    let mid = (low + high)/2

    if canMove(for: mid) {
        mostWeight = mid
        low = mid+1
    } else {
        high = mid-1
    }
}

func canMove(for weight: Int) -> Bool {
    var visited = Set<Int>([ab[0]])
    var q: [Int] = [ab[0]]
    
    while !q.isEmpty {
        let curr = q.removeFirst()
        for (island, w) in islands[curr] where w >= weight {
            if island == ab[1] {
                return true
            }
            guard !visited.contains(island) else { continue }
            visited.insert(island)
            q.append(island)
        }
    }
    return false
}

print(mostWeight)

 

배운점

풀이 자체보다도 이해가 어려웠던 문제였다!!!!! 그리고 메모리 제한..... 후 너무 고통스러웠다 ㅠㅠ