[파이썬] 백준 2258 : 정육점 (골드4)
2258번: 정육점
첫째 줄에 두 정수 N(1 ≤ N ≤ 100,000), M(1 ≤ M ≤ 2,147,483,647)이 주어진다. N은 덩어리의 개수를 의미하고, M은 은혜가 필요한 고기의 양이다. 다음 N개의 줄에는 각 고기 덩어리의 무게와 가격을 나
www.acmicpc.net
문제
풀이
0. 방향성 생각
- 특정 가격 고기를 사면 싼 고기를 모두 고를 수 있다.
- table[가격] = [무게1, 무게2, ...] 이런식으로 나타내서 무게 역순으로 정렬하기.
- 긴 배열에서 가격 연산을 줄이기 위해서 누적 합 사용.
1. 입력
from collections import defaultdict as dd
import sys
input = lambda : sys.stdin.readline().rstrip()
n,goal = map(int,input().split())
info = [list(map(int,input().split())) for _ in range(n)]
table = dd(list)
for w,p in info:
table[p].append(w)
- 일단 무게 순으로 받기 위해서 defaultdict에 가격 추가해주기
2. 누적 합 만들어주기
table_sum = dd(list)
total_w = 0
for p in table:
table[p].sort(reverse=True)
for i in table[p]:
if table_sum[p]:
table_sum[p].append(table_sum[p][-1]+i)
else:
table_sum[p].append(i)
total_w += table_sum[p][-1]
- table_sum에 누적 합 가격 저장해주기
- total_w에 정육점에서 파는 전체 무게 저장해주기
3. 출력
if total_w < goal:
print(-1)
else:
now = 0
answer = []
for p in sorted(table_sum.keys()):
cumul = table_sum[p]
if now + cumul[-1] < goal:
now += cumul[-1]
else:
for count,w in enumerate(cumul):
if now + w >= goal:
answer.append(p*(count+1))
break
now += cumul[-1]
print(min(answer))
- 정육점에서 파는 전체 무게보다 목표로 하는 무게가 크면 -1 출력
- 그렇지 않은 경우에는 현재 구매한 고기의 양을 나타낸 now, 정답 후보를 넣을 answer 리스트 정의
- 현재 가격으로 판매하는 모든 고기(cumul[-1])를 구매해도 goal에 못미치는 경우, 고기를 무료로 받는다.
(현재 가격 p보다 비싼 고기를 구매하는 순간 공짜로 얻을 수 있다.) - 현재 가격으로 판매하는 모든 고기를 구매해 goal을 달성하는 경우, 현재 가격으로 판매하는 고기를 하나씩 탐색한다.
- cumul에는 누적 고기무게가 저장되어있다,
- now에 현재 누적 고기량 w을 더해서 goal에 달성하는 경우 현재 고기까지만 구매한 후 고기를 몇 개 샀는지 계산 (인덱스 count+1를 통해서 몇 개 샀는지 계산한다)
- 특정 가격대의 고기를 사서 goal을 만족했더라도, 더 비싼 고기를 사서 더 적은 비용으로 고기를 살 수 있는 경우가 있으므로 끝까지 순회해주기.
이를 위해서 특정 가격대의 탐색이 끝나면 현재 구매한 고기 now에 cumul[-1] (가격대 고기 전부)를 더해준다.
전체코드
from collections import defaultdict as dd
import sys
input = lambda : sys.stdin.readline().rstrip()
n,goal = map(int,input().split())
info = [list(map(int,input().split())) for _ in range(n)]
table = dd(list)
for w,p in info:
table[p].append(w)
table_sum = dd(list)
total_w = 0
for p in table:
table[p].sort(reverse=True)
for i in table[p]:
if table_sum[p]:
table_sum[p].append(table_sum[p][-1]+i)
else:
table_sum[p].append(i)
total_w += table_sum[p][-1]
if total_w < goal:
print(-1)
else:
now = 0
answer = []
for p in sorted(table_sum.keys()):
cumul = table_sum[p]
if now + cumul[-1] < goal:
now += cumul[-1]
else:
for count,w in enumerate(cumul):
if now + w >= goal:
answer.append(p*(count+1))
break
now += cumul[-1]
print(min(answer))
코멘트
마땅한 풀이가 생각 안나서 일주일쯤 고민한듯....
'Algorithm > Greedy' 카테고리의 다른 글
[파이썬] 백준 30015 : 학생회 뽑기 (골드3) (0) | 2024.01.17 |
---|---|
[파이썬] 백준 13904 : 과제 (골드3) (0) | 2023.12.19 |
[파이썬] 백준 2109 : 순회강연 (골드3) (0) | 2023.12.12 |
[파이썬] 백준 1781 : 컵라면 (골드2) (0) | 2023.11.30 |
[파이썬] 백준 28709 : 와일드카드 괄호 문자열 (골드1) (0) | 2023.10.22 |
[파이썬] 백준 18513 : 샘터 (골드4) (0) | 2023.10.22 |
[파이썬] 프로그래머스 : 단속카메라 (Lv.3) (0) | 2023.08.18 |
댓글