Skip to content

Commit 8400b5c

Browse files
grayroomtony9402
andauthored
[ADD] baekjoon 21944 python solution (#95)
* [ADD] baekjoon 21944 python solution * [ADD] baekjoon 21944 python solution * Refactoring --------- Co-authored-by: Minsang Kim <[email protected]>
1 parent 579eceb commit 8400b5c

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

solutions/baekjoon/21944/main.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Authored by : leejh9226
2+
# Co-authored by : -
3+
# Link : http://boj.kr/171a010d7b2247588d9dba8b3fa192c2
4+
5+
import heapq
6+
import sys
7+
8+
def input():
9+
return sys.stdin.readline().rstrip()
10+
11+
12+
max_g_heap = [[] for _ in range(101)]
13+
min_g_heap = [[] for _ in range(101)]
14+
max_l_heap = [[] for _ in range(101)]
15+
min_l_heap = [[] for _ in range(101)]
16+
17+
l_lookup = [0] * 100001
18+
g_lookup = [0] * 100001
19+
20+
removed = set()
21+
22+
23+
def add(p, l, g):
24+
"""
25+
recommend에서 사용할 수 있도록 알고리즘 유형, 난이도별로 생성해둔 최소, 최대힙에 문제를 추가
26+
27+
Q. 삭제된 적이 있지만 아직 heap에 해당 문제가 남아있을 수 있지 않나요?
28+
A. heap에는 삭제된 문제가 남아있을 수 있어, 동일한 문제를 추가하면 해당 heap에는 똑같은 문제 2개가 존재하게 됨. 하지만 이후 해당
29+
문제를 다시한번 삭제한 다음 조회하는 경우 두 문제 모두 efficient_top_g 함수에서 제거되기 때문에 문제가 발생하지 않음. 문제를 다시
30+
삭제하기 이전이라면, 둘 중 어떤 문제(인스턴스)가 조회되더라도 동일한 답이 나오기 때문에 문제가 발생하지 않음.
31+
"""
32+
33+
# 각각 100001, 101보다 큰 2진수 값(2**17, 2**7)을 곱하여 integer값 하나에 3가지 정보를 담음. 이 값을 lpg라고 명명
34+
lpg = l << 24 | p << 7 | g
35+
36+
# 동일한 난이도, 문제번호, 알고리즘 유형의 문제가 이미 삭제된 적이 있다면, 삭제된 기록을 제거
37+
if is_removed(lpg):
38+
removed.remove(lpg)
39+
40+
# 난이도 > 문제번호 > 알고리즘 유형 우선순위로 정렬(최소, 최대힙)
41+
heapq.heappush(max_g_heap[G], -lpg)
42+
heapq.heappush(min_g_heap[G], lpg)
43+
heapq.heappush(max_l_heap[L], -lpg)
44+
heapq.heappush(min_l_heap[L], lpg)
45+
# solved에서 사용할 수 있도록 문제번호-난이도, 문제번호-알고리즘 유형 매핑 정보를 저장
46+
l_lookup[P] = l
47+
g_lookup[P] = g
48+
49+
50+
def remove(p, l, g):
51+
"""
52+
난이도, 문제번호, 알고리즘 유형으로 식별되는 유일한 문제를 "삭제되었음"으로 표시
53+
- 실제 힙에서 삭제하는 동작은, recommend에서 heappop을 호출할 때 "삭제되었음"으로 표시된 문제를 제거하는 것
54+
"""
55+
removed.add(l << 24 | p << 7 | g)
56+
57+
58+
def is_removed(lpg):
59+
"""
60+
난이도, 문제번호, 알고리즘 유형으로 식별되는 유일한 문제가 제거되었는지 확인
61+
max_heap에서는 음수 값으로 저장되어 있으므로, 절대값을 취한 뒤 비교
62+
"""
63+
if abs(lpg) in removed:
64+
return True
65+
return False
66+
67+
68+
def efficient_top(target_heap):
69+
"""
70+
최상위 문제가 이미 제거된 문제라면, 최상위 문제를 제거하고 다음 최상위 문제를 찾음
71+
삭제되지 않고, 조건을 만족하는 문제가 존재한다면, 문제번호를 반환
72+
"""
73+
while target_heap and is_removed(target_heap[0]):
74+
heapq.heappop(target_heap)
75+
76+
if target_heap:
77+
return (abs(target_heap[0]) >> 7) & 0x1FFFF
78+
return None
79+
80+
81+
n = int(input())
82+
for _ in range(n):
83+
P, L, G = map(int, input().split())
84+
add(P, L, G)
85+
86+
q = int(input())
87+
for _ in range(q):
88+
cmd = input().split()
89+
90+
# case 분기
91+
match cmd[0]:
92+
case "recommend":
93+
"""
94+
recommend G x
95+
x가 1인경우 -> 알고리즘 분류가 G인 문제중 가장 어려운것 출력
96+
조건을 만족하는 문제가 많다면 문제번호가 큰것
97+
x가 -1인경우 -> 알고리즘 분류가 G인 문제중 가장 쉬운것 출력
98+
조건을 만족하는 문제가 많다면 문제번호가 작은것
99+
100+
알고리즘 분류 G마다 각각의 최대, 최소힙을 사용하여 문제를 저장한다.
101+
- 힙 정렬 기준은 난이도 > 문제번호 > 알고리즘 분류 순서대로
102+
- 알고리즘 분류를 포함한 이유는, 힙에서 꺼낸 문제를 유일하게 식별하여 이미 풀린 문제인지 확인하기 위함
103+
"""
104+
G, x = int(cmd[1]), int(cmd[2])
105+
if x == 1:
106+
print(efficient_top(max_g_heap[G]))
107+
else:
108+
print(efficient_top(min_g_heap[G]))
109+
case "recommend2":
110+
"""
111+
recommend2 x
112+
x가 1인경우 -> 가장 어려운 문제 출력
113+
조건을 만족하는 문제가 많다면 문제번호가 큰것
114+
x가 -1인경우 -> 가장 쉬운 문제 출력
115+
조건을 만족하는 문제가 많다면 문제번호가 작은것
116+
117+
난이도 L마다 각각의 최대, 최소힙을 사용하여 문제를 저장한다.
118+
- 힙 정렬 기준은 난이도 > 문제번호 > 알고리즘 분류 순서대로
119+
- 난이도를 포함한 이유는, 힙에서 꺼낸 문제를 유일하게 식별하여 이미 풀린 문제인지 확인하기 위함
120+
- x == 1인 경우 -> 난이도 100부터 1까지 순회하며, 해당 난이도에서 문제번호가 가장 큰 문제를 출력
121+
- x == -1인 경우 -> 난이도 1부터 100까지 순회하며, 해당 난이도에서 문제번호가 가장 작은 문제를 출력
122+
"""
123+
x = int(cmd[1])
124+
if x == 1:
125+
for i in range(100, 0, -1):
126+
if (a := efficient_top(max_l_heap[i])) is not None:
127+
print(a)
128+
break
129+
else:
130+
for i in range(1, 101, 1):
131+
if (a := efficient_top(min_l_heap[i])) is not None:
132+
print(a)
133+
break
134+
case "recommend3":
135+
"""
136+
recommend3 x L
137+
x가 1인경우 -> 난이도가 L이상인 문제 중 가장 쉬운것 출력
138+
조건을 만족하는 문제가 많다면 문제번호가 작은것
139+
없다면 -1 출력
140+
x가 -1인경우 -> 난이도가 L미만인 문제 중 가장 어려운것 출력
141+
조건을 만족하는 문제가 많다면 문제번호가 큰것
142+
없다면 -1 출력
143+
144+
난이도 L마다 각각의 최대, 최소힙을 사용하여 문제를 저장한다.
145+
- 힙 정렬 기준은 난이도 > 문제번호 > 알고리즘 분류 순서대로
146+
- 난이도를 포함한 이유는, 힙에서 꺼낸 문제를 유일하게 식별하여 이미 풀린 문제인지 확인하기 위함
147+
- x == 1인 경우 -> 난이도 L부터 100까지 순회하며, 해당 난이도에서 문제번호가 가장 작은 문제를 출력
148+
- x == -1인 경우 -> 난이도 L-1부터 1까지 순회하며, 해당 난이도에서 문제번호가 가장 큰 문제를 출력
149+
"""
150+
x, L = int(cmd[1]), int(cmd[2])
151+
if x == 1:
152+
for i in range(L, 101):
153+
if (a := efficient_top(min_l_heap[i])) is not None:
154+
print(a)
155+
break
156+
else:
157+
print(-1)
158+
else:
159+
for i in range(L - 1, 0, -1):
160+
if (a := efficient_top(max_l_heap[i])) is not None:
161+
print(a)
162+
break
163+
else:
164+
print(-1)
165+
case "add":
166+
P, L, G = int(cmd[1]), int(cmd[2]), int(cmd[3])
167+
add(P, L, G)
168+
case _: # "solved"
169+
P = int(cmd[1])
170+
remove(P, l_lookup[P], g_lookup[P])
171+
172+
""" Solution Description
173+
알고리즘 유형, 난이도별로 최대, 최소힙을 사용하여 문제를 저장하고, 힙에서 문제를 꺼낼 때 이미 삭제된 문제인지 확인한 다음, 조건에
174+
맞게 문제 번호를 출력했습니다.
175+
"""

0 commit comments

Comments
 (0)