새소식

반응형
Algotithms

[백준] 16508 전공책

  • -
728x90
반응형

문제

      • 전공책 제목에서 알파벳을 오려내서 원하는 단어를 만드려고 한다. 이때 비용은 사용한 전공책의 가격의 합이다.
        • 1 <= |문자열의 길이| <= 10
        • 1 <= 전공책의 개수 <= 16
        • 1 <= |전공책 제목의 길이| <= 50
      • 만약 단어를 만들 수 없다면 -1 출력하기

 

풀이 1

      • 그리디하게 풀 수 없다!
        • 35000원 짜리 1개, 40000원 짜리 1개 보다는 40000원 짜리 책에서 2개 알파벳 뽑아야 최소비용이니까!
      • 완전탐색 문제 (모든 경우의 수 확인하기)
        • 각 전공책을 포함한다 / 안한다 2개의 경우로 생각해 전체 경우를 확인한다.
        • 시간복잡도 : $2^{16}$ 이므로 충분히 계산 가능하다.
      • 카운터와 비트마스크를 이용해 각 경우의 수 마다 문자열을 만들 수 있는지 체크하고, 가능하다면 최솟값 갱신
        • 1. 문자열 T에 대한 알파벳 개수 abc_list에 저장하고,
        • 2. 각 경우의 수마다 전공 책에 있는 알파벳을 abc_list 에서 뺀다. (카운터는 - 연산 가능!)
        • 3. abc_list 가 비었다면, 문자열 T를 만들 수 있다는 의미이므로 최솟값을 갱신한다.
      • 91% 에서 시간 초과..!!
from collections import Counter
import sys
from copy import deepcopy

T = input()
N = int(input())
books = []              # 책 리스트 (가격, 책제목의 알파벳 개수)
for _ in range(N):
    price, title = input().split()
    books.append((int(price), Counter(title)))

abc_list = Counter(T)   # 문자열 T에서 각 알파벳의 개수
answer = sys.maxsize

# 00..0 ~ 11...1 까지 각 전공책이 포함 되고 포함되지 않는 경우의 수 확인
for i in range(1 << N):
    price = 0
    alphabets = deepcopy(abc_list)  # 문자열 만드는데 필요한 알파벳 개수

    for j in range(N):
        if (i & 1 << j) != 0 :          # j 번째 전공책이 포함된 경우
            price += books[j][0]        # 가격 더하고
            alphabets -= books[j][1]    # 알파벳 개수 제외
    
    if not alphabets :  # 문자열을 만들 수 있다면 최솟값 저장
        answer = min(answer, price)

print(-1) if answer == sys.maxsize else print(answer)

 

풀이 2

  • deepcopy 때문이라고 생각해서 deepcopy 없이 확인하는 함수를 만들었다.

 

from collections import Counter
import sys

#  문자열을 만들 수 있는지 확인하기
def check(alphabets, string):
    for w in string :
        # 없는 알파벳이거나, 더이상 추가할 수 없다면 실패
        if w not in alphabets or alphabets[w] == 0 :
            return False
        else:
            alphabets[w] -= 1   # 알파벳 숫자 줄이기
    return True
            
T = input()
N = int(input())
books = []              # 책 리스트 (가격, 책제목의 알파벳 개수)
for _ in range(N):
    price, title = input().split()
    books.append((int(price), Counter(title)))

answer = sys.maxsize

# 00..0 ~ 11...1 까지 각 전공책이 포함 되고 포함되지 않는 경우의 수 확인
for i in range(1 << N):
    price = 0
    alphabets = Counter()      # 전공책의 알파벳들

    for j in range(N):
        if (i & 1 << j) != 0 :          # j 번째 전공책이 포함된 경우
            price += books[j][0]        # 가격 더하고
            alphabets += books[j][1]    # 문자열 더하기
    
    if check(alphabets, T) :  # 문자열을 만들 수 있다면 최솟값 저장
        answer = min(answer, price)

print(-1) if answer == sys.maxsize else print(answer)

 

 

References

    • 백준 16508
    • 2023.04.28 오늘의 문제
반응형

'Algotithms' 카테고리의 다른 글

[백준] 1072 게임  (0) 2023.04.29
[백준] 1005 ACM Craft  (0) 2023.04.29
[백준] 15886 내 선물을 받아줘 2  (0) 2023.04.28
[백준] 1021 회전하는 큐  (0) 2023.04.28
[백준] 17144 미세먼지 안녕!  (0) 2023.04.27
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.