これは単純な動的計画問題です。
全長N
をとし、タスクの長さをL
。
サブF(T)
間隔から選択できるタスクの最大数とすると(T, N)
、各単位時間Tで、次の3つの可能性があります。
- Tから始まるタスクはありません。
- Tから始まるタスクがありますが、結果セットには含まれていません。
- Tから始まるタスクがあり、それを結果セットに含めます。
ケース1は単純で、次のようになりますF(T) = F(T + 1)
。
ケース2/3の場合、開始するタスクを選択すると、このタスクの実行中に開始するすべてのタスクを拒否する必要があることに注意してください。T
つまり、T
との間T + L
です。だから私たちは得るF(T) = max(F(T + 1), F(T + L) + 1)
。
最後に、F(N) = 0
。つまり、最初から始めてF(N)
、に戻っていくだけF(0)
です。
編集:これにより、間隔の最大数が得られますが、2つの制約を満たすセットは得られません。制約についてのあなたの説明は私には不明確なので、そこであなたを助ける方法がわかりません。特に、サンプルセットのすべての解が明らかに等しいため、制約1が何を意味するのかわかりません。
編集2:要求に応じていくつかのさらなる説明:
あなたの投稿された例を考えてみましょN = 11
うL = 2
。で始まるタスクがありますT = 0, 3, 4, 5, 6, 9
。開始しF(11) = 0
て逆方向に作業する:
F(11) = 0
F(10) = F(11) = 0
(でタスクが開始されないためT = 10
)
F(9) = max(F(10), F(11) + 1) = 1
- ..。
最終的に私たちはに到達しF(0) = 4
ます:
T |00|01|02|03|04|05|06|07|08|09|10|
F(T)| 4| 3| 3| 3| 3| 2| 2| 1| 1| 1| 0|
編集3:まあ、私はこれについて十分に興味があったので、解決策を書いたので、それを投稿したほうがいいかもしれません。これにより、タスクが最も多く、ギャップの数が最も少なく、最小のギャップが最小のセットが得られます。質問の例の出力は次のとおりです。
(0, 2) -> (4, 6) -> (6, 8) -> (9, 11)
(0, 2) -> (4, 6) -> (8, 10)
明らかに、私は正確さについて保証しません!:)
プライベートクラスTask{publicint Start {get; セットする; } public int Length {get; セットする; } public int End {get {return Start + Length; }}
public override string ToString()
{
return string.Format("({0:d}, {1:d})", Start, End);
}
}
private class CacheEntry : IComparable
{
public int Tasks { get; set; }
public int Gaps { get; set; }
public int MinGap { get; set; }
public Task Task { get; set; }
public Task NextTask { get; set; }
public int CompareTo(object obj)
{
var other = obj as CacheEntry;
if (Tasks != other.Tasks)
return Tasks - other.Tasks; // More tasks is better
if (Gaps != other.Gaps)
return other.Gaps = Gaps; // Less gaps is better
return MinGap - other.MinGap; // Larger minimum gap is better
}
}
private static IList<Task> F(IList<Task> tasks)
{
var end = tasks.Max(x => x.End);
var tasksByTime = tasks.ToLookup(x => x.Start);
var cache = new List<CacheEntry>[end + 1];
cache[end] = new List<CacheEntry> { new CacheEntry { Tasks = 0, Gaps = 0, MinGap = end + 1 } };
for (int t = end - 1; t >= 0; t--)
{
if (!tasksByTime.Contains(t))
{
cache[t] = cache[t + 1];
continue;
}
foreach (var task in tasksByTime[t])
{
var oldCEs = cache[t + task.Length];
var firstOldCE = oldCEs.First();
var lastOldCE = oldCEs.Last();
var newCE = new CacheEntry
{
Tasks = firstOldCE.Tasks + 1,
Task = task,
Gaps = firstOldCE.Gaps,
MinGap = firstOldCE.MinGap
};
// If there is a task that starts at time T + L, then that will always
// be the best option for us, as it will have one less Gap than the others
if (firstOldCE.Task == null || firstOldCE.Task.Start == task.End)
{
newCE.NextTask = firstOldCE.Task;
}
// Otherwise we want the one that maximises MinGap.
else
{
var ce = oldCEs.OrderBy(x => Math.Min(x.Task.Start - newCE.Task.End, x.MinGap)).Last();
newCE.NextTask = ce.Task;
newCE.Gaps++;
newCE.MinGap = Math.Min(ce.MinGap, ce.Task.Start - task.End);
}
var toComp = cache[t] ?? cache[t + 1];
if (newCE.CompareTo(toComp.First()) < 0)
{
cache[t] = toComp;
}
else
{
var ceList = new List<CacheEntry> { newCE };
// We need to keep track of all subsolutions X that start on the interval [T, T+L] that
// have an equal number of tasks and gaps, but a possibly a smaller MinGap. This is
// because an earlier task may have an even smaller gap to this task.
int idx = newCE.Task.Start + 1;
while (idx < newCE.Task.End)
{
toComp = cache[idx];
if
(
newCE.Tasks == toComp.First().Tasks &&
newCE.Gaps == toComp.First().Gaps &&
newCE.MinGap >= toComp.First().MinGap
)
{
ceList.AddRange(toComp);
idx += toComp.First().Task.End;
}
else
idx++;
}
cache[t] = ceList;
}
}
}
var rv = new List<Task>();
var curr = cache[0].First();
while (true)
{
rv.Add(curr.Task);
if (curr.NextTask == null) break;
curr = cache[curr.NextTask.Start].First();
}
return rv;
}
public static void Main()
{
IList<Task> tasks, sol;
tasks = new List<Task>
{
new Task { Start = 0, Length = 2 },
new Task { Start = 3, Length = 2 },
new Task { Start = 4, Length = 2 },
new Task { Start = 5, Length = 2 },
new Task { Start = 6, Length = 2 },
new Task { Start = 9, Length = 2 },
};
sol = F(tasks);
foreach (var task in sol)
Console.Out.WriteLine(task);
Console.Out.WriteLine();
tasks = new List<Task>
{
new Task { Start = 0, Length = 2 },
new Task { Start = 3, Length = 2 },
new Task { Start = 4, Length = 2 },
new Task { Start = 8, Length = 2 },
};
sol = F(tasks);
foreach (var task in sol)
Console.Out.WriteLine(task);
Console.Out.WriteLine();
tasks = new List<Task>
{
new Task { Start = 0, Length = 5 },
new Task { Start = 6, Length = 5 },
new Task { Start = 7, Length = 3 },
new Task { Start = 8, Length = 9 },
new Task { Start = 19, Length = 1 },
};
sol = F(tasks);
foreach (var task in sol)
Console.Out.WriteLine(task);
Console.Out.WriteLine();
Console.In.ReadLine();
}