어떤 회사의 작업공정은 아래에서 위로 진행됩니다. 밑의 직원들이 일을 모두 끝내야 상사가 작업을 전달받아 할 수 있는 방식입니다. 각 직원에게는 한 명의 직속 상사만 있으며, 모든 작업은 단위 시간이 걸립니다. 이제 회사에서 일부 직원을 해고하려 할 때 최소 작업 완료 시간과, 원래의 작업시간을 유지하면서 해고할 수 있는 최대 인원 수를 구하세요.
일단 문제를 읽어보니 회사 형태는 트리 그래프로 그려지겠습니다.
위 그래프는 예제를 나타낸 것입니다. 원래 최소 작업 완료 시간은 트리의 높이가 되겠군요. 모든 작업에 단위 시간 1이 소요된다고 할 때, 최소 작업 완료 시간은 결국 루트 노드에서 가장 멀리 떨어진 리프 노드의 깊이입니다. (루트를 1부터 계산) 예제에서 작업 완료 시간은 3입니다.
이제 남은 문제는 최소 인원을 찾는 건데, 이건 한참을 고민해야 했습니다.
음, 그냥 특정 레벨에 노드 수가 가장 많다면 그게 최소 인원 아닐까? 예제로 보자면 말단 업무가 4개니까 4명 남기고 다 해고하면 되겠네요.
하지만 그게 그리 쉬운 일이 아니었습니다.
위 그래프에서 특정 레벨에서 가장 많은 노드의 수를 찾으면 6입니다. 하지만 약간의 변형을 거치면…
4명만 있어도 최소 작업 완료 시간 내에 모든 작업을 할 수 있게 됩니다. 단순히 어떤 조건을 만족하는 노드의 수를 찾는 건 정답이 될 수는 없었습니다.
그럼 일단 노드를 깊이 순으로 넣어놓고 하나하나 옮겨봐야 할까, 하는 초보적인 방식도 떠올려보다가 하나 떠오른 생각이 있었죠.
방법은 단순합니다. 주어진 트리에 대해, 리프 노드를 모두 골라냅니다. 그리고 깊이가 깊은 순으로 제한된 인원 수 만큼 작업을 실시합니다. 그리고 완료된 작업 노드를 제거한 후, 다시 리프 노드를 고르고, 깊이 순으로 작업을 해줍니다. 그리고 이 절차를 반복하여 모든 작업이 완료될 때까지 걸린 시간이 바로 최적 작업 완료 시간 아닐까요.
일단 예시 그래프에서 3개씩 작업을 해낸다고 해봅시다.
최소 작업 완료 시간 내에 모든 노드를 제거하지 못했습니다. 이번엔 4개씩 해봅시다.
성공입니다! 이 그래프의 최소 인원 수는 4입니다.
그런데 문제는 이겁니다.
인원 \(K\)로 최소 작업 시간 내 완료가 가능하다와 최소 작업 시간 내에 완료되면 \(K\)는 최소 인원 수이다라는 명제는 동치가 아닙니다. 인원 수 \(K\)는 최소 인원이다와 인원 수 \(K\)로 항상 최소 작업 시간 내 완료가 가능하다도 또한 동치가 아닐 가능성은 있죠.
결국 논리의 허점에 막혀 허우적대던 차에 논문 하나를 발견했으니, 바로 Hu의 스케줄링입니다.
Hu's algorithm을 적용하기 위한 조건은 다음과 같습니다:
DAG여야 한다. (Directed Acyclic Graph, 방향 있는 트리는 DAG임)
모든 작업의 소요 시간은 동일한 단위여야 한다. (문제의 모든 작업은 단위 시간 1 소요)
모든 작업은 임의의 프로세서에 배정 가능하다. (문제의 작업은 상사, 부하 다 할 수 있음)
모든 조건이 부합하니, 스케줄링을 하면 되겠군요.
스케줄링 방법은 제가 떠올린 방법과 같습니다. 우선순위대로 집어넣는 탐욕법으로 진행됩니다.
IBM 연구원이 고안한 이 알고리즘은 특정 작업 용량으로 스케줄링을 할 때 최적 시간 내 작업이 완료됨을 보장합니다. Hu의 원 논문에선 상당히 복잡한 수식으로 증명되어 있는데, McHugh의 논문에선 훨씬 단순하게 증명되어 있습니다.
인원 \(K\)로 항상 최적 작업 완료 시간 내 완료 가능하므로 이제 \(K\)가 최소 필요 인원일 때, 항상 최소 작업 완료 시간 내 완료 가능하다라는 명제는 참이 되었습니다. 최소 필요 인원은 이분 탐색으로 찾아줍시다.
스케줄링은 위상정렬로 뼈대를 만들어놓고 껍데기를 씌우는 식으로 할 겁니다.
위 알고리즘은 시간복잡도 면에서 비교적 저렴한 편에 속하는 이분탐색, 위상정렬, 우선순위 큐로만 이루어져 있습니다. 실제 시간복잡도는 \(O(N \log^2 N)\)로, TLE를 받을 정도는 아닙니다.
예제는 어찌저찌 잘 통과하는데, 안타깝게도 이 코드는 통과하지 못했습니다. 혹시 어떤 조건이 잘못된 게 아닌가 싶어 여기저기 assert까지 집어넣어봤으나 그런 건 아닌 것 같습니다. 연구원들조차 알지 못했던 기막힌 반례라도 있는 건지 아니면 제가 문제를 잘못 이해하고 있는 것인지조차 헷갈리기 시작하는군요. 틈날 때마다 코드를 손봐서 제출해봤지만, 아무래도 통과할 기미가 보이지 않습니다.