[백준] 1450 냅색문제

2024. 10. 15. 12:03·PS/백준
반응형

문제

https://www.acmicpc.net/problem/1450

입력

n: Int = 물건의 개수
c: Int = 가방의 용량
arr: [Int] = 물건의 무게들

1 <= n <= 30 

1 <= c <= 10^9

1 <= arr[i] <= 10^9

결과

ans: Int = 가방에 넣는 방법의 수

해석

n이 크지 않아 조합으로 도전하려 했지만  ({{30}C_1} ~ {{30}C_{30}}) 까지 구한다고 하면 너무 많은 시간이 걸릴 것
같아 실패했다.

 

여기서 비슷하게 느꼇던 문제가 생각났는데 바로 아래 문제다.

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

이 문제는 두 플레이어가 주사위들을 나눠가진 후 그 주사위 눈들의 합을 합쳐 승/무/패를 계산하는 문제이다.

 

여기서 모든 주사위 조합을 구한 후 마지막에 A의 주사위를 가지고 B의 승무패를 이진 탐색으로 계산했다. 

 

이 문제도 비슷한 것 같다.

 

n을 반씩 나누어서 시간복잡도를 줄일 수 있다.


예를 들어 [1, 2, 3, 4] 라는 무게가 주어졌고 c = 5라고 해보자.


[1, 2]와 [3, 4]를 나누어서 가방에 넣을지 말지를 고민한다.

 

[1, 2] 에 대해서 경우의 수를 구한다면 4개가 나올 것이고, 각각 무게는 [0, 1, 2, 3]이 나온다.
[3, 4] 에 대해서 경우의 수를 구한다면 4개가 나올 것이고, 각각 무게는 [0, 3, 4, 7]이 나온다.

이제 이 두가지 무게를 가지고 가방에 넣는 방법을 구할 수 있다.

 

[3, 4]에 대해 구한 무게를 가지고 접근해보자.

[3, 4] 일 때,

  1. 가방에 0을 넣으면 [1, 2]에서는 [0, 1, 2, 3] 총 4개를 넣을 수 있다. target = 5 - 0
  2. 가방에 3을 넣으면 [1, 2]에서는 [0, 1, 2] 총 3개를 넣을 수 있다. target = 5 - 3 = 2
  3. 가방에 4를 넣으면 [1, 2]에서는 [0, 1] 총 2개를 넣을 수 있다. target = 5 - 4 =  1 
  4. 가방에 7을 넣으면 [1, 2]에서는 아무것도 넣을 수 없다. target = 5 -7 = -2

그러면 4 + 3 + 2 총 9개의 경우의 수가 존재하게 된다.

 

여기서 보면 [0,1,2,3] 덩어리에 더 큰 값을 넣을 수록 짧아지는 것을 볼 수 있다

 

즉,  target = c - 현재 넣을려는 무게 일 때,  [0,1,2,3] 덩어리에서 target보다  = upperbound 바로 전 까지

 

여기서 보면 4 직전까지 몇개의 원소가 있는 지 궁금하면 

3에 대한 upperbound를 찾으면된다 = 첫 4의 index = 6  ,  그냥 upperbound자체가 정답이된다.

index가 0부터 시작하는 특성때문에 이득본 것 

 

우리는 그러면 크게 두 단계의 작업을 해야한다.

 

  1. 무게를 2등분 하여 나올 수 있는 모든 합을 구한다.  (dfs) 
  2. 이분 탐색을 통해 upperbound를 구한다.

 

코드

import Foundation

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

let (n,c) = (nc[0], nc[1])

let weights: [Int] = readLine()!.split{$0 == " "}.map{Int($0)!}

var sumArray1: [Int] = []
var sumArray2: [Int] = []

func dfs(from i: Int , to j: Int, array: inout [Int], weight: Int) {

    if weight > c  { // 무게 초과 조합 실패
        return
    }
    
    if i == j { // 목표 도달 시 종료
        array.append(weight)
        return
    }
    
    // 해당 무게를 골랐을 때랑 고르지 않을 때 , 두 갈림길로 분기
    dfs(from: i+1, to: j, array: &array, weight: weight+weights[i])
    dfs(from: i+1, to: j, array: &array, weight: weight)
    
}

dfs(from: 0, to: n/2, array: &sumArray1, weight: 0)
dfs(from: n/2, to: n, array: &sumArray2, weight: 0)

sumArray1.sort()

func bsUpperbound(arr: [Int], target: Int) -> Int {
    
    var start = 0
    var end = arr.count
    
    while start < end {
        let mid = (start+end) / 2
        
        if arr[mid] > target { end = mid }
        else { start = mid + 1}
        
    }
    
    return end
}

var ans: Int = 0

for sum2 in sumArray2 {
    ans += bsUpperbound(arr: sumArray1, target: c-sum2) // sum2를 가방에 담고 남은 공간을 sumArray1 조합으로 채워야하므로  c-sum2
}
print(ans)

 

참고

 

[BOJ] 백준 1450 냅색문제 (Swift)

문제 https://www.acmicpc.net/problem/1450 1450번: 냅색문제 첫째 줄에 N과 C가 주어진다. N은 30보다 작거나 같은 자연수, C는 109보다 작거나 같은 음이 아닌 정수이다. 둘째 줄에 물건의 무게가 주어진다.

dev-mandos.tistory.com

 

 

이진 탐색 ( + 하한 lower_bound, 상한upper_bound )

1. 이진 탐색 정렬된 데이터에서 특정 값을 찾는 알고리즘탐색 범위를 반으로 줄여가며 찾기 떄문에 O(lgN) 으로 빠르게 동작한다. 만약 정렬된 데이터에 찾고자하는 수가 중복으로 있다면 가장

keepgoing0328.tistory.com

 

반응형

'PS > 백준' 카테고리의 다른 글

[백준] 11724 연결 요소의 개수  (1) 2024.10.15
[백준] 2667 단지번호붙이기  (1) 2024.10.15
[백준] 1806 부분합  (0) 2024.10.14
[백준] 2470 두 용액  (0) 2024.10.14
[백준] 3273 두 수의 합  (0) 2024.10.14
'PS/백준' 카테고리의 다른 글
  • [백준] 11724 연결 요소의 개수
  • [백준] 2667 단지번호붙이기
  • [백준] 1806 부분합
  • [백준] 2470 두 용액
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (339)
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (41)
        • swift (34)
        • python (6)
        • Kotlin (1)
      • iOS (134)
        • UIKit (37)
        • Combine (1)
        • SwiftUI (34)
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (1)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (21)
        • 어노테이션 (6)
        • 튜토리얼 (14)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (21)
        • 이론 (10)
        • MCP (1)
        • LangGraph (10)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Swift
    프로그래머스
    AVFoundation
    concurrency
    dp
    CS
    lifecycle
    투포인터
    protocol
    Spring
    boostcamp
    IOS
    dfs
    dispatch
    SwiftUI
    Tuist
    백준
    GIT
    UIKit
    property
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
[백준] 1450 냅색문제
상단으로

티스토리툴바