時間間隔のリストが与えられた場合、重複しない最大間隔のセットを見つける必要があります。
例えば、
次の間隔がある場合:
[0600, 0830], [0800, 0900], [0900, 1100], [0900, 1130],
[1030, 1400], [1230, 1400]
また、時間は[0000, 2400]
の範囲内でなければならないことが与えられています。
重複しない間隔の最大セットは[0600, 0830], [0900, 1130], [1230, 1400]
です。
最大セットパッキングがNP完全であることを理解しています。問題(開始時間と終了時間のみを含む間隔)もNP完全であるかどうかを確認したいと思います。
もしそうなら、指数関数的な時間で最適なソリューションを見つける方法がありますが、よりスマートな前処理とデータのプルーニングを使用します。または、固定パラメータの扱いやすいアルゴリズムを実装するのが比較的簡単な場合。近似アルゴリズムには行きたくありません。
これはNP完全問題ではありません。この問題を解決するために動的計画法を使用するO(n * log(n))
アルゴリズムを考えることができます。
N個の間隔があるとします。与えられた範囲がS
(あなたの場合は_S = [0000, 2400]
_)であると仮定します。すべての間隔がS
内にあると仮定するか、線形時間でS
内にないすべての間隔を削除します。
前処理:
A[n]
_を取得するとします。O(n * log(n))
時間がかかりますn
整数の配列_Next[n]
_を取得するとします。i,
_の終了点に存在しない場合、n
を_Next[i]
_に割り当てることができます。O(n * log(n))
時間内に実行でき、バイナリ検索を使用して答えを見つけます。これを解決するための線形アプローチが存在するかもしれませんが、前のステップではすでにO(n * log(n))
時間がかかるため、問題ではありません。DP:
[A[i].begin, S.end]
_の重複しない最大間隔が_f[i]
_であると仮定します。次に、_f[0]
_が必要な答えです。f[n] = 0
_;f[i] = max{f[i+1], 1 + f[Next[i]]}
_上記の解決策は、私が問題を一目見たときに思いついたものです。その後、私はより単純な貪欲なアプローチも考えます(ただし、大きなO表記の意味では速くはありません)。
(上記のDPアプローチと同じ表記法と仮定で)
前処理:すべての間隔をendポイントで並べ替えます。 n間隔の配列_B[n]
_を取得するとします。
貪欲:
_int ans = 0, cursor = S.begin;
for(int i = 0; i < n; i++){
if(B[i].begin >= cursor){
ans++;
cursor = B[i].end;
}
}
_
上記の2つの解決策は私の頭から浮かびますが、あなたの問題はアクティビティ選択問題とも呼ばれ、ウィキペディアで見つけることができます http://en.wikipedia.org/wiki/Activity_selection_problem 。
また、アルゴリズムの概要では、この問題について16.1で詳しく説明しています。