링크 : https://www.acmicpc.net/problem/23059
23059번: 리그 오브 레게노
첫째 줄에는 백남이가 알고 있는 아이템 사이의 관계의 수 $N$(1 ≤ $N$ ≤ 200,000)를 입력받는다. $N$개의 줄에 걸쳐서 아이템 이름을 의미하는 문자열 2개 A B가 주어진다. 아이템 A는 아이템 B를 구
www.acmicpc.net
코드
from collections import defaultdict
from heapq import heappop,heappush
n = int(input())
item = defaultdict(list) # a를 사면 b를 살 수 있다.
depth = defaultdict(int)
allItem = set()
for _ in range(n):
a,b = input().split()
allItem.update({a,b})
item[a].append(b)
depth[b] += 1
zeroDepth = []
for x in allItem :
if depth[x] == 0:
heappush(zeroDepth,x)
popedItem, tmp = [],[]
while zeroDepth:
popedItem.append(node := heappop(zeroDepth))
for nextNode in sorted(item[node]):
depth[nextNode] -= 1
if depth[nextNode] == 0:
heappush(tmp,nextNode)
if not zeroDepth:
if not tmp: break
zeroDepth = tmp
tmp = []
if len(popedItem) != len(allItem):
print(-1)
else:
for x in popedItem:
print(x)
사용 알고리즘
" 위상-정렬 + 우선순위큐 "
풀이
이 문제의 핵심은 딱 두가지이다.
- 아이템 사이에는 미리 정해진 순서가 존재한다.
- 현재 구매할 수 있는 아이템 중 아직 구매하지 않은 아이템을 '모두' 찾고 그 아이템들을 사전순으로 '모두' 구매한다.
1번 조건은 단순한 위상-정렬 알고리즘으로 충분히 해결이 가능하다. 하지만 여기서 문제가 되는 점은 2번이다.
현재 구매할 수 있는 아이템을 모두 찾는다는 말은 먼저 구매해야 할 아이템이 이미 모두 구입된 아이템들을 찾는다는 말이고, 사전순으로 모두 구매한다는 말은 그 아이템들을 정렬하여 그 순서대로 모두 구매해야 한다는 것이다.
만약 구매할 수 있는 아이템을 찾을 때마다 모두 사전순으로 정렬하게 된다면 시간복잡도가 크게 올라갈 것이다. 따라서 우선순위큐를 사용했다.
while zeroDepth:
popedItem.append(node := heappop(zeroDepth))
for nextNode in sorted(item[node]):
depth[nextNode] -= 1
if depth[nextNode] == 0:
heappush(tmp,nextNode)
if not zeroDepth:
if not tmp: break
zeroDepth = tmp
tmp = []
먼저 구매할 수 있는 아이템들을 모두 찾고 사전순으로 하나씩 탐색하였다. 해당 아이템을 구매함으로써 구매가 가능해진 아이템의 목록을 따로 저장하고 이전에 찾은 아이템을 모두 사용하기 위해서 구매할 수 있는 아이템이더라도 이전 아이템 목록을 모두 구매한 뒤 새로 추가하였다.
'알고리즘 > BAEKJOON (Python)' 카테고리의 다른 글
[ 백준 / P5 / 파이썬 Python ] 정점들의 거리 (1) | 2023.05.12 |
---|---|
[ 백준 / G4 / Pypy3 ] 15961번 - 회전초밥 (2) | 2023.05.11 |
[ 백준 / G2 / Python 파이썬 ] 네트워크 복구 (0) | 2023.05.08 |
[ 백준 / 골드3 / 파이썬 Python ] 1516번 - 게임 개발 (0) | 2023.04.13 |
[ 백준 / 골드5 / 파이썬 Python ] Knapsack Problem ( 14728번-벼락치기, 9084번-동전 ) (0) | 2023.04.12 |