Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python에서 주어진 제약 조건으로 모든 작업을 완료하는 최소 시간 찾기

서로 다른 소요 시간을 가진 여러 작업(job)의 배열이 있고, 이를 수행할 k명의 담당자가 있다고 가정해 봅시다. 또한 각 담당자가 작업 한 단위를 처리하는 데 걸리는 시간 t도 주어집니다. 우리는 다음과 같은 제약 조건 하에 모든 작업을 완료하는 데 필요한 최소 시간을 구해야 합니다.

  • 한 명의 담당자에게는 연속된 작업만 배정할 수 있습니다.

  • 두 명의 담당자가 하나의 작업을 나누어 수행하거나 공유할 수 없습니다.

예를 들어, 입력이 k = 4, t = 5, job = {12, 6, 9, 15, 5, 9}라면 출력은 75가 됩니다. 이는 [12], [6, 9], [15], [5, 9]와 같이 작업을 네 명의 담당자에게 배정했을 때 얻을 수 있는 총 소요 시간입니다.

접근 방법: 이진 탐색 활용

이 문제는 이진 탐색(Binary Search)을 활용하면 효율적으로 해결할 수 있습니다. 핵심 아이디어는 "주어진 시간 안에 k명의 담당자로 모든 작업을 완료할 수 있는가?"를 판단하는 유효성 검사 함수를 만들고, 가능한 시간 범위(0부터 모든 작업 시간의 합까지)에서 이진 탐색을 수행하는 것입니다. 어떤 시간 X로 작업 완료가 가능하다면 X보다 큰 시간으로도 항상 가능하기 때문에, 탐색 범위를 절반씩 줄여나갈 수 있습니다.

1. 유효성 검사 함수 (is_valid)

is_valid() 함수는 특정 시간(time) 내에 K명의 담당자로 모든 작업을 완료할 수 있는지 확인합니다. 동작 과정은 다음과 같습니다.

  • n := job 배열의 크기

  • count := 1 (필요한 담당자 수), curr_time := 0 (현재 담당자의 누적 작업 시간), i := 0

  • i < n인 동안 반복:

    • curr_time + job[i] > time이면 → 새로운 담당자가 필요하므로 curr_time := 0, count := count + 1

    • 그렇지 않으면 → 현재 담당자에게 작업을 추가: curr_time := curr_time + job[i], i := i + 1

  • count <= K이면 true 반환

2. 메인 함수 (get_minimum_time)

  • n := job 배열의 크기

  • end := 모든 작업 시간의 합, begin := 0

  • res := end (초기 결과값)

  • job_max := job 배열의 최댓값 (가장 오래 걸리는 단일 작업 — 이 값보다 작은 시간으로는 해당 작업을 완료할 수 없음)

  • begin <= end인 동안 이진 탐색 반복:

    • mid := ((begin + end) / 2)의 정수 부분

    • mid >= job_max이고 is_valid(mid, K, job)가 참이면 → res := min(res, mid), end := mid - 1 (더 작은 시간 탐색)

    • 그렇지 않으면 → begin := mid + 1 (더 큰 시간 탐색)

  • res * T 반환 (작업 단위당 실제 소요 시간 T를 곱해 최종 결과 계산)

구현 예시

아래 파이썬 코드를 통해 더 잘 이해해 봅시다.

def is_valid(time, K, job):
    n = len(job)
    count = 1
    curr_time = 0
    i = 0
    while i < n:
        if curr_time + job[i] > time:
            curr_time = 0
            count += 1
        else:
            curr_time += job[i]
            i += 1
    return count <= K


def get_minimum_time(K, T, job):
    n = len(job)
    end = 0
    begin = 0
    for i in range(n):
        end += job[i]
    res = end
    job_max = max(job)
    while begin <= end:
        mid = int((begin + end) / 2)
        if mid >= job_max and is_valid(mid, K, job):
            res = min(res, mid)
            end = mid - 1
        else:
            begin = mid + 1
    return res * T


job = [12, 6, 9, 15, 5, 9]
k = 4
T = 5
print(get_minimum_time(k, T, job))

입력

4, 5, [12, 6, 9, 15, 5, 9]

출력

75

복잡도 분석

  • 시간 복잡도: O(n × log S) — S는 모든 작업 시간의 합입니다. 매번 이진 탐색 범위가 절반으로 줄어들고, 각 단계마다 O(n)의 유효성 검사를 수행합니다.

  • 공간 복잡도: O(1) — 추가적인 배열 없이 상수 개의 변수만 사용합니다.

이처럼 이진 탐색과 그리디한 유효성 검사를 결합하면, 모든 경우의 수를 확인하는 비효율적인 방법 대신 빠르게 최소 완료 시간을 구할 수 있습니다.