Maximimum disjoint ranges
Abridged problem statement
Given ranges, pick a subset of ranges , maximizing , such that, for any two ranges , .
In other words, pick as many ranges as you can while ensuring that no two of them intersect.
Solution
There is no natural next step we can perform in order to solve this problem. Perhaps a greedy strategy will work? What if we simply pick the first occuring interval every single time? Does this maximize the number of intervals we pick?
Turns out, no. Seeing why is pretty easy too. Consider this case:
Our strategy would pick the interval , and then , achieving . It is clear that we can achieve , however, by picking the blue intervals instead.
So… what do we do?
The right move in most greedy problems is to ‘fix’ the right variable. With this in mind, let us try fixing the time we arrive at the festival, that is, the time after which we can start picking intervals. In fact, let us define a function that denotes the maximum number of intervals we can pick if we can only pick intervals that start at or after .
The point of doing this is to notice only one thing: that is monotonic. Indeed, for any value of . This is because the set of intervals associated with is bigger than that associated with , so, if was currently worse, we could just pick the same set of intervals picked by to get them to be equal.
Now, out of out the intervals available to us at , let us try picking all of them. Then, we get
We could now proceed with some sort of dynamic programming solution; do note that we don’t need to explicitly exclude the interval we selected as it will not be re-included in , because , and—but wait! We don’t need to do any of that, because we already know that is maximized for the smallest . So, we can just pick such that is the smallest possible.
Then, we discard intervals with and proceed with calculating in the exact same way!
Exchange argument
While this solution is complete, with proof, I’ll present another way to prove the same result. Formally, what we are saying is that there exists at least one optimal that contains , where is minimized.
The way we prove this is by considering an arbitrary . Now, we proceed to transform to another set , with the hope that . This method of proving greedy algorithms is popularly known as an exchange argument.
So let us do this. Consider an arbitrary set .
Now, if contains , we’re done. Otherwise, sort the intervals contained in by their right endpoints, and consider the first one. Call this interval .
We note that . Let us make . Now:
- is now the first interval in .
- Since , and did not intersect with any other intervals in , will not either.
Therefore, we have managed to construct with , proving that an optimal set containing must always exist.
For readers not convinced by the rigour of this proof, we are essentially imagining a huge set of sets of all the possible ways to pick intervals (potentially many). In this set, we want to prove that our target set () is the maximum element. We do this by showing, for every other element in the set (), that .
Code
Here’s how we implement this in C++:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> a(n);
for (auto &[s, e] : a) {
cin >> s >> e;
}
sort(a.begin(), a.end(), [&](const pair<int, int> &a, const pair<int, int> &b) {
return a.second < b.second;
});
int ans = 0;
int t = 0;
for (auto &[s, e] : a) {
if (s < t) {
continue;
}
ans++;
t = e;
}
cout << ans << '\n';
}