Algorithm/BOJ

백준 1450 냅색문제

삼쓰 웅쓰 2021. 4. 6. 14:48
728x90

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

분류: 이분탐색


접근방식

n이 30으로 크기 때문에 그대로 부분합을 구하면 2^30 시간제한을 통과하기 어렵습니다.

따라서 반반 나눈 뒤 이분탐색으로 접근하는 방법으로 접근합니다.

 

부분합은 재귀적으로 구해줬습니다.

func partition(_ idx: Int, _ to: Int, _ array: inout [Int], _ sum: Int) {
    guard sum <= nc[1] else { return }
    guard idx < to else { array.append(sum); return }
    
    partition(idx+1, to, &array, sum + products[idx])
    partition(idx+1, to, &array, sum)
}

var sumA = [Int]()
var sumB = [Int]()
partition(0, products.count/2, &sumA, 0)
partition(products.count/2, products.count, &sumB, 0)

 

 

이렇게 반을 나눠 부분합을 구했다면, 

한 쪽에서 부분합을 선택하고 나머지 배열에서 몇 개를 넣을 수 있는지 세어주면 됩니다.

func binarySearchUpperBounds(target: Int) -> Int {
    var low = 0
    var high = sumB.count
    
    while low < high {
        let mid = (low + high)/2
        if target < sumB[mid] {
            high = mid
        } else {
            low = mid+1
        }
    }
    
    return low
}

 

참고로 처음에 예제의 답이 왜 3인지 몰랐었는데요, 배낭에 아무것도 넣지 않는 경우도 하나의 경우로 생각해줘야 합니다 :)

 

해결방법

let nc = readLine()!.split(separator: " ").map { Int(String($0))! }
let products = readLine()!.split(separator: " ").map { Int(String($0))! }

func partition(_ idx: Int, _ to: Int, _ array: inout [Int], _ sum: Int) {
    guard sum <= nc[1] else { return }
    guard idx < to else { array.append(sum); return }
    
    partition(idx+1, to, &array, sum + products[idx])
    partition(idx+1, to, &array, sum)
}

var sumA = [Int]()
var sumB = [Int]()
partition(0, products.count/2, &sumA, 0)
partition(products.count/2, products.count, &sumB, 0)

sumB.sort()

func binarySearchUpperBounds(target: Int) -> Int {
    var low = 0
    var high = sumB.count
    
    while low < high {
        let mid = (low + high)/2
        if target < sumB[mid] {
            high = mid
        } else {
            low = mid+1
        }
    }
    
    return low
}

var getCase = 0
for a in sumA {
    
    let upper = binarySearchUpperBounds(target: nc[1] - a)
    getCase += upper
}

print(getCase)

 

배운점

이런 방식을 meet in the middle 방법이라고 한다더라.