백준(BOJ) 시뮬레이션 문제집: 화장실의 규칙(골드 5)
문제 출처: https://www.acmicpc.net/problem/19640
19640번: 화장실의 규칙
위와 같이 줄을 선 경우를 생각해보자. (x, y) 는 사원의 근무 일수가 x, 화장실이 급한 정도가 y임을 나타낸다. [x, y]는 해당 사원이 데카임을 의미한다. 즉, 위의 그림에서 데카는 3번 사원이다.
www.acmicpc.net
1. 알고리즘
처음에 단순히 생각해서 시간초과가 났었다. 이것때문에 고생 좀 했지만...우선순위 큐 잘 사용해서 계속 앞 사람에 대해 찾지 않도록 하면 통과할 것이라고 생각함.
- 대기하는 사람만큼 입력을 받아 서게 될 줄번호를 계산하고 해당 줄에 (근무일수*(-1), 화장실이 급한 정도*(-1), 줄 번호, 사람 번호) 형태로 데이터를 삽입
- 우선순위 큐를 선언, 큐에 각 줄의 가장 맨 앞 사람을 대기줄 리스트에서 뽑아 삽입함.
- 화장실에 간 사람이 데카일 때까지 while 반복
- 큐에서 가장 우선순위가 높은 사람을 뽑아 화장실에 보냄
- 화장실에 간 사람+1
- 화장실에 간 사람이 서 있던 줄의 두번째로 서 있던 사람(=가장 앞 순서로 올 사람)을 뽑아 큐에 추가
- 데카 앞에 몇 사람이 화장실에 갔는지 출력
2. 유의사항
- 우선순위에 맞게 정렬할 때, 매번 앞 줄의 사람을 찾으면 시간초과 문제가 날 것.
3. 어려웠던 점, 해결방법
- 시간초과
- 매번 앞 줄 사람 찾기 > 우선순위 큐에 맨 앞 사람들 넣어놓고, 갱신되는 사람 줄에서만 추가하기
-
#시간초과 코드 while worker != (K+1): #대기줄의 가장 앞 사람을 뽑아옴 worker_candidate = [wl[0] for wl in waiting_lines if wl and wl[0]] #정렬 worker_candidate.sort(reverse=True) #가장 맨 앞의 사람을 화장실에 보낼 직원으로 선정 out_worker = worker_candidate[0] #화장실에 간 직원을 대기열에서 삭제 waiting_lines[(M-out_worker[2])].popleft() #화장실에 간 직원의 사람번호 worker = out_worker[3] #화장실에 간 사람+1 count += 1
- 우선순위 큐 정렬
- 각 값마다 크고 작은 수의 우선순위가 달랐다. > 클 수록 우선순위가 높은 경우에는 -1을 곱했음
4. 소스코드
자세한 설명은 주석 참조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import sys
from collections import deque
from queue import PriorityQueue
input_func = sys.stdin.readline
if __name__ == '__main__':
N, M, K = map(int, input_func().split())
waiting_lines, idx = [deque() for _ in range(M)], 0
#사람 수만큼 반복, 대기줄에 넣어줌
for n in range(N):
D, H = map(int, input_func().split())
#줄번호 계산
line_number = idx%M
#대기줄의 줄번호에 사람(-근무일수, -급한 정도, 줄번호, 사람번호) 추가
waiting_lines[line_number].append((D*(-1), H*(-1), line_number, n+1))
idx += 1
#화장실에 갈 후보군 우선순위 큐 선언
out_queue = PriorityQueue()
#맨 처음의 후보들 큐에 삽입
for idx in range(M):
if waiting_lines[idx]:
next_worker = waiting_lines[idx].popleft()
out_queue.put(next_worker)
worker, count = -1, 0
#화장실에 간 직원이 데카가 아닐 때 반복
while worker != (K+1):
#우선순위 큐에서 가장 우선순위가 높은 직원 데이터를 빼낸다.
_, _, out_worker_line, worker = out_queue.get()
#화장실에 간 사람+1
count += 1
#만약 화장실에 간 직원이 서 있던 줄에 다음 사람이 줄 서 있으면
if waiting_lines[out_worker_line]:
#그 줄의 다음 사람 데이터를 뽑아와 큐에 삽입
next_worker = waiting_lines[out_worker_line].popleft()
out_queue.put(next_worker)
#전체 화장실에 간 사람 - 데카 출력
print(count-1)
|
cs |
5. 고민
'Algorithms > 백준' 카테고리의 다른 글
[백준_1013]Contact with Python (0) | 2021.06.24 |
---|---|
[백준_1747]소수&팰린드롬 with Python (0) | 2021.06.23 |
[백준_20165]인내의 도미노 장인 호석 with Python (0) | 2021.06.16 |
[백준_17178]줄서기 with Python (0) | 2021.06.03 |
[백준_3709]레이저빔은 어디로 with Python (0) | 2021.06.01 |
댓글