프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

각 상담 유형에 적절하게 담당 멘토를 배치해서 참가자들의 대기 시간을 최소화 하는 문제입니다.

 

제공되는 파라미터들의 범위가 크지 않으므로 완전탐색을 이용해 보겠습니다.

 

순서는 다음과 같습니다.

 

1. 멘토 배치가 가능한 경우의 수 모두 생성
2. 각 경우의 수 마다 발생하는 대기시간 계산
3. 최소의 대기시간을 구하여 반환

 


 

우선 첫번째, 배치 가능한 경우의 수를 생성합니다.

from itertools import product

for mento_distribute in product(range(1, n+1), repeat=k):
        if sum(mento_distribute) == n:
            waiting_time = check_time(mento_distribute, k, reqs)
            answer = min(answer, waiting_time)
 

Python / Itertools Product / 카테시안 곱

product 함수의 기능 Itertools 라이브러리에 내장된 함수 중 한 개인 product 함수는 카테시안 곱(Cartesian product)을 계산합니다. 즉, 입력된 여러 개의 iterables 객체 간의 모든 가능한 조합을 생성합니다.

kimmimo.tistory.com

[1 ~ n] 객체를 repeat = 3 하도록 product 했다고 가정해보면

 

ex) [1, 2, 2] = 1번 유형: 1명 | 2번 유형: 2명 | 3번 유형: 2

       [3, 1, 1] = 1번 유형: 3명 | 2번 유형: 1명 | 3번 유형: 1

 

라고 해석할 수 있습니다.

 

총 멘토가 n명이 있었으므로 product 객체 내의 수는 그 합이 n이 되어야 합니다.

 

그러므로 product의 총 합, sum(product 객체) == n 인 경우에만 취급합니다.

 

이렇게 생성된 멘토 배치의 경우의 수를 가지고 대기 시간을 계산해주겠습니다.

 

 


 

import heapq

def check_time(mento_distribute, k, reqs):
    mento = []
    waiting = 0
    
    for n in mento_distribute:
        mento.append([0 for x in range(n)])
        
    for s, f, num in reqs:
        time = heapq.heappop(mento[num-1])
        waiting += max(0, time-s)
        heapq.heappush(mento[num-1], max(s, time)+f)
    
    return waiting

mento 리스트는 현재 활동중인 멘토들이 상담이 끝나는 시간을 저장해줄 공간입니다.

 

이 때 끝나는 시간의 최소값을 빠르게 구할 필요가 있으므로 heapq의 형태를 사용해 주겠습니다.

 

Python / 힙 자료구조 / heapq

heapq 힙은 우선순위 큐(priority queue)를 구현하는 데 사용되며, 정렬된 순서를 유지하면서 요소를 빠르게 삽입하고 삭제할 수 있게 해줍니다. 파이썬에서는 heapq 라이브러리를 통해 이러한 힙 구조

kimmimo.tistory.com

초기에는 아직 멘토가 활동중이지 않다고 가정하고 각 유형마다 배정된 멘토의 수 만큼 0으로 초기화 해주겠습니다.

ex) [1, 2, 2] => [0]         => 1번 유형

                             [0, 0]     => 2번 유형

                             [0, 0]     => 3번 유형

 

이제 상담 요청 리스트로부터 요청을 한 개씩 꺼내와서 상담사를 배치해 주겠습니다.

 

각 유형에 해당하는 멘토들 중 가장 먼저 상담이 끝나는 상담사를 찾습니다.

 

이 때 mento 리스트에 저장된 값이 가장 작은 (= 상담이 가장 일찍 끝나는)값을 heappop 함수로 꺼내와 줍니다.

 

만약 그 값이 현재 상담을 요청한 사람이 도착한 시간, s 보다 크다는 것은 대기시간이 발생한다는 의미입니다.

 

만약 대기시간이 발생한다면 (상담 끝나는 시간 - 도착시간)을, 아니라면 0을 총 대기시간에 더해줍니다.

 

이제 요청자가 상담을 받는다고 가정하고 상담이 끝나는 시간을 새롭게 계산해서 mento 리스트에 넣어줄 것입니다.

 

새로운 상담 종료 시간은 (상담 시작 시간 + 상담 소요 시간)이 될 것입니다.

 

상담 시작 시간은 요청자가 도착한 시간상담자가 상담이 끝나는 시간더 큰 값이 들어가게 됩니다.

 

heappush를 사용하여 다시 mento리스트에 상담이 끝나는 시간을 넣어줍니다.

 

이를 모든 요청동안 반복한 뒤 마지막에 쌓인 대기시간 waiting을 반환해줍니다.

 


전체 코드

import heapq
from itertools import product

def check_time(mento_distribute, k, reqs):
    mento = []
    waiting = 0
    
    for n in mento_distribute:
        mento.append([0 for x in range(n)])
        
    for s, f, num in reqs:
        time = heapq.heappop(mento[num-1])
        waiting += max(0, time-s)
        heapq.heappush(mento[num-1], max(s, time)+f)
    
    return waiting
    
def solution(k, n, reqs):
    answer = float("inf")
    
    for mento_distribute in product(range(1, n+1), repeat=k):
        if sum(mento_distribute) == n:
            waiting_time = check_time(mento_distribute, k, reqs)
            answer = min(answer, waiting_time)
    
    return answer