Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Elementary Algorithms / Greedy and Scheduling

1.3.3 Interval Partitioning

1-Elementary-Algorithms/1.3.3_Interval_Partitioning.cpp

View on GitHub

Assigns intervals to the minimum number of groups so that no two intervals in the same group overlap. This is the classic interval partitioning problem, also known as finding the minimum number of rooms needed for meetings.

The greedy algorithm sorts intervals by start time and reuses the group whose current finish time is earliest whenever possible. Otherwise, it creates a new group.

  • interval_partitioning(intervals) returns a vector room, where room[id] is the assigned room for each input interval given as a vector of PartitionInterval with fields start, finish, and id. The number of rooms used in the returned assignment is $1 + \max({\htmlClass{math-inline-code}{\texttt{room[id]}}})$, or 0 if there are no intervals.

Implementation

#include <algorithm>
#include <functional>
#include <queue>
#include <utility>
#include <vector>

struct PartitionInterval {
  int start, finish, id;
};

std::vector<int> interval_partitioning(std::vector<PartitionInterval> intervals) {
  std::sort(
      intervals.begin(), intervals.end(),
      [](const PartitionInterval &a, const PartitionInterval &b) {
        return a.start != b.start ? a.start < b.start : a.finish < b.finish;
      }
  );
  std::vector<int> room(intervals.size());
  std::priority_queue<
      std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>>
      pq;
  int rooms = 0;
  for (const auto &[start, finish, id] : intervals) {
    if (!pq.empty() && pq.top().first <= start) {
      int r = pq.top().second;
      pq.pop();
      room[id] = r;
    } else {
      room[id] = rooms++;
    }
    pq.emplace(finish, room[id]);
  }
  return room;
}

Example Usage

#include <algorithm>
#include <cassert>
using namespace std;

int main() {
  vector<PartitionInterval> intervals{{0, 30, 0}, {5, 10, 1}, {15, 20, 2}};
  vector<int> room = interval_partitioning(intervals);
  assert(1 + *max_element(room.begin(), room.end()) == 2);
  assert(room[1] == room[2]);
  assert(room[0] != room[1]);
  return 0;
}