백준 1106 - 호텔

Computer Science/Problem Solving

문제 설명

제한사항 및 입출력

풀이

문제 요약은 다음과 같다. 각 도시에서 광고에 cost원을 쓰면 people명의 고객을 얻는다. 최소 C명 이상의 고객을 모으기 위해 써야 하는 최소 비용을 구하라. 같은 도시는 여러 번 사용할 수 있다.

전형적인 배낭 문제이다. 핵심은 “같은 아이템(도시)을 무한히 쓸 수 있음” -> 완전 배낭 형태이다. 또한 “정확히 C명”이 아니라 “C명 이상”을 만족하면 된다.

직관적으로 봤을 때 그리디로도 접근할 수 있을 것 같이 생겼지만 초과분의 존재 때문에 최적해를 보장할 수 없다.

 

dp테이블의 정의는 다음과 같이 내렸다.

dp[i] = i명을 모으는 데 드는 최소 비용

또한 초과해서 모아도 되기 때문에 한 번에 모을 수 있는 최대 비용을 여유분으로 넉넉하게 지정해주었다.

내 코드

import sys
input = sys.stdin.readline
mis = lambda: map(int, input().split())
INF = float('inf')

# c명 늘리기 위해 투자해야하는 돈의 최솟값
c, n = mis()
arr = [[*mis()] for _ in range(n)]

# dp[i] = i명 모으는데 드는 최소 비용
limit = c + max(arr, key= lambda x:x[1])[1]
dp = [INF] * (limit+1)
dp[0] = 0

for i, j in arr:
    for x in range(j, limit+1):
        dp[x] = min(dp[x], dp[x-j] + i)

print(min(dp[c:]))

같은 도시를 여러 번 사용할 수 있기 때문에 도시를 앞에서부터 순회하며 dp 테이블의 상태를 전이해주었다.

각 도시에 대해 모든 dp 테이블을 순회하며 앞에서 해당 도시를 사용한 경우와 이미 채워진 값을 비교하여 더 작은 값으로 갱신하여 통과했다.

고찰

이런 배낭 문제는 각 아이템을 몇 번이나 반복해서 사용할 수 있는지에 대한 여부가 굉장히 중요하다. 자주 나오는 선택 가능 횟수를 분류해보자면 다음 두 가지가 있고, dp의 정의는 공통적으로 다음과 같다.


1차원 dp: dp[w] = 용량 w에서의 최대 가치
2차원 dp: dp[i][w] = i번째 아이템까지 고려했을 때, 용량 w에서의 최적값

 

1차원으로의 dp 압축은 루프 방향으로 “dp[w - wt_i]가 이번 라운드에서의 갱신 여부”를 통제해, 아이템의 중복을 허용할지 결정한다.

1. 0/1 배낭

  • 각 아이템 최대 1개 선택 가능
  • 전이
    1차원: dp[w] = max(dp[w], dp[w-wt[i]] + val[i]) ->  w를 뒤에서 앞으로 순회
    2차원: dp[i][w] = max(dp[i-1][w], dp[i-1][w - wt_i] + val_i) -> 전부 이전 층을 확인해서 아이템 i는 최대 한 번 사용

2. 완전 배낭

  • 같은 아이템을 여러 번 사용 가능
  • 전이
    1차원: dp[w] = max(dp[w], dp[w-wt[i]] + val[i]) -> w를 앞에서 뒤로 순회
    2차원: dp[i][w] = max(dp[i-1][w], dp[i][w - wt_i] + val_i) -> i층을 또 확인 가능

2차원 dp 테이블을 채우는 것도 O(n^2)의 시간 복잡도가 필요하기 때문에 공간 복잡도가 유리한 1차원 dp로 풀이하도록 하자!

'Computer Science > Problem Solving' 카테고리의 다른 글

백준 21278 - 호석이 두 마리 치킨  (0) 2025.09.18
백준 16946 - 벽 부수고 이동하기 4  (0) 2025.09.14
백준 12969 - ABC  (1) 2025.09.05
백준 20924 - 트리의 기둥과 가지  (0) 2025.09.04
백준 9421 - 소수상근수  (0) 2025.09.03
'Computer Science/Problem Solving' 카테고리의 다른 글
  • 백준 21278 - 호석이 두 마리 치킨
  • 백준 16946 - 벽 부수고 이동하기 4
  • 백준 12969 - ABC
  • 백준 20924 - 트리의 기둥과 가지
hojoo
hojoo
그냥 개발이 즐거운 사람
  • hojoo
    dev_record
    hojoo
  • 전체
    오늘
    어제
    • 분류 전체보기 (82)
      • Study (0)
        • 모든 개발자를 위한 HTTP 웹 기본 지식 (0)
        • Real MySQL 8.0 (0)
        • 친절한 SQL 튜닝 (0)
        • 도메인 주도 개발 시작하기 (0)
        • 대규모 시스템 설계 기초 (0)
      • Computer Science (66)
        • Problem Solving (30)
        • Data Structure (4)
        • Spring Boot (13)
        • DB (1)
        • Java (4)
        • OS (3)
        • Server (2)
        • Tech (0)
      • Security (16)
        • Reversing (15)
        • Assembly (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    소수상근수
    서버 증설 횟수
    리버싱
    bean
    DB
    PE header
    19622
    Spring boot
    Header
    dreamhack.io
    2539
    자료구조
    DP
    리버싱 핵심원리
    9421
    n+1
    13265
    16946
    servlet
    21278
    12033
    n^2 배열 자르기
    x64dbg
    15973
    백준
    레나 튜토리얼
    Lena tutorial
    HTTP
    Reversing
    프로그래머스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
hojoo
백준 1106 - 호텔
상단으로

티스토리툴바