区間スケジューリング問題
区間スケジューリング問題とは以下のような問題である.
N個のタスクの集合が与えられる.各タスクiについて開始時刻s[i]と終了時刻f[i]が定められている.任意の時刻において重複がないようにタスクを選ぶ場合,最大でいくつのタスクを選ぶことができるか.
この問題は,貪欲法により,O(NlogN)で解くことができる.
説明
終了時刻の早いものから順に重複しない限り選ぶことを繰り返すという貪欲法によってこの問題を解くことができる.
証明
この問題に対する解に含まれる集合をOPTとし,以降,OPTに含まれるタスクを終了時刻でソートしてOPT={i1,i2,...,io}と表現する.
また,貪欲法により選んだタスクの集合も同様にG={j1,j2,...,jg}と表現する.まず,
補題 1
∀k≤o:f[jk]≤f[ik]
を数学的帰納法により示す.
補題1の証明
k=1について,貪欲法が最も終了時刻の早いタスクを選択することから,f[j1]≤f[i1]となることは自明である.
k=mについて,f[jm]≤f[im]が成り立つと仮定する.ここで,f[jm]≤f[im]≤s[im+1]が成り立つ.仮にf[im+1]<f[jm+1]なら,貪欲法でim+1が選択されるため,f[jm+1]≤f[im+1]が成り立つ.
したがって,数学的帰納法より,補題1が示された.最後に,
定理
上記貪欲法がこの問題に対する解である.
を背理法により示す.
上記貪欲法で選択したタスクの集合が解でないと仮定する.
Gに最後に追加されたタスクjgについて,補題1より,
f[jg]≤f[ig]
が成り立つ.ここで,仮定より|G|<|OPT|であるが,
f[jg]≤f[ig]≤s[ig+1]
となり,これは,貪欲法のアルゴリズムで最後にタスクjgを加えた後もタスクig+1が残っていることを示しているが,上記貪欲法のアルゴリズムと矛盾する.
よって,背理法より,上記貪欲法で選択したタスクの集合がこの問題の解であることが示された.
コード
int interval_scheduling_problem(vector<pair<i64, i64>> &tasks) {
sort(all(tasks), [](pair<i64, i64> &a, pair<i64, i64> &b) {
return a.second < b.second;
});
int ret = 0;
i64 now = 0;
for (pair<i64, i64> &e: tasks) {
if (e.first > now) {
ret++;
now = e.second;
}
}
return ret;
}