[BOJ/py] 15961 회전초밥

햅쌀이·2023년 6월 2일
1

✍🏻 Algorithm

목록 보기
16/22
post-thumbnail

문제 링크 https://www.acmicpc.net/problem/15961

📝 문제

문제 설명
회전 초밥 음식점에는 회전하는 벨트 위에 여러 가지 종류의 초밥이 접시에 담겨 놓여 있고, 손님은 이 중에서 자기가 좋아하는 초밥을 골라서 먹는다. 초밥의 종류를 번호로 표현할 때, 다음 그림은 회전 초밥 음식점의 벨트 상태의 예를 보여주고 있다. 벨트 위에는 같은 종류의 초밥이 둘 이상 있을 수 있다.

새로 문을 연 회전 초밥 음식점이 불경기로 영업이 어려워서, 다음과 같이 두 가지 행사를 통해서 매상을 올리고자 한다.

1.원래 회전 초밥은 손님이 마음대로 초밥을 고르고, 먹은 초밥만큼 식대를 계산하지만, 벨트의 임의의 한 위치부터 k개의 접시를 연속해서 먹을 경우 할인된 정액 가격으로 제공한다.
2.각 고객에게 초밥의 종류 하나가 쓰인 쿠폰을 발행하고, 1번 행사에 참가할 경우 이 쿠폰에 적혀진 종류의 초밥 하나를 추가로 무료로 제공한다. 만약 이 번호에 적혀진 초밥이 현재 벨트 위에 없을 경우, 요리사가 새로 만들어 손님에게 제공한다.
위 할인 행사에 참여하여 가능한 한 다양한 종류의 초밥을 먹으려고 한다. 위 그림의 예를 가지고 생각해보자. k=4이고, 30번 초밥을 쿠폰으로 받았다고 가정하자. 쿠폰을 고려하지 않으면 4가지 다른 초밥을 먹을 수 있는 경우는 (9, 7, 30, 2), (30, 2, 7, 9), (2, 7, 9, 25) 세 가지 경우가 있는데, 30번 초밥을 추가로 쿠폰으로 먹을 수 있으므로 (2, 7, 9, 25)를 고르면 5가지 종류의 초밥을 먹을 수 있다.

회전 초밥 음식점의 벨트 상태, 메뉴에 있는 초밥의 가짓수, 연속해서 먹는 접시의 개수, 쿠폰 번호가 주어졌을 때, 손님이 먹을 수 있는 초밥 가짓수의 최댓값을 구하는 프로그램을 작성하시오.

💻 코드

import sys
input = sys.stdin.readline
from collections import defaultdict

N, M, K, coupon = map(int, input().split())
sushi = list(int(input()) for _ in range(N))
sushi += sushi[:K-1]

max_cnt = 0
cnt_sushi = defaultdict(int)
cnt_sushi[coupon] += 1

for i in range(K):
    cnt_sushi[sushi[i]] += 1

for i in range(K, len(sushi)):
    cnt_sushi[sushi[i-K]] -= 1
    if cnt_sushi[sushi[i-K]] == 0:
        del cnt_sushi[sushi[i-K]]

    cnt_sushi[sushi[i]] += 1

    max_cnt = max(max_cnt, len(cnt_sushi))

print(max_cnt)

📌 해결방법

  1. 회전초밥은 원형으로 이루어져 있기때문에 기존 회전초밥 배열에
    sushi[:K-1] 를 더해주기
  2. 1번 조건은 무조건 만족한다고 생각하고, 쿠폰의 초밥은 이미 먹은것으로 가정
  3. dict를 사용해 초밥이 0이 된다면 key를 삭제함
  4. 남은 dict 길이를 구하면 끝

💡 배운 점

- defaultdict()

  • from collections import defaultdict 추가 후 사용
  • 기존 딕셔너리 배열에서는 key값이 있는지 확인 후 접근하여야 함!!
    (안그러면 keyerror 발생)
  • defaultdict()는 딕셔너리에 key가 존재하지 않아도 에러를 발생하지 않고 자료형의 초기값을 세팅해줌.
  • defaultdict(int) 매개변수로 int를 추가하면 초기값을 0으로 세팅

✔ 느낀 점

처음에는 deque와 set을 사용하여 구현하려고 했었는데 계속 시간초과가 났다...

cnt_sushi = deque()
cnt_sushi.append(coupon)
for i in range(K):
    cnt_sushi.append(sushi[i])

max_cnt = len(set(cnt_sushi))

for i in range(K, N):
    cnt_sushi.append(coupon)
    cnt_sushi.append(sushi[i])
    cnt_sushi.popleft()

    if len(set(cnt_sushi)) > max_cnt:
        max_cnt = len(set(cnt_sushi))

print(max_cnt)

그래서 딕셔너리 자료형을 생각했는데 key 삭제하는 법을 몰라가지고..^^
del을 쓰면 되는지 처음 알았네;;
암튼 그렇게 풀었는데 이제는 시간초과는 안나오는데 틀렸다고 나와서 낙담....
계속 찾다보니 for i in range(K, len(sushi)): 이 부분에서 sushi 배열을 추가했는데 범위를 수정안하고 for i in range(K, N): 이라고 해둬서 그런거였다............ 덜렁대지 말자 증말

profile
C++과 파이썬 공부중

2개의 댓글

comment-user-thumbnail
2023년 6월 3일

회전초밥,,,, 저도 먹고 싶습니다!!

1개의 답글