Найти наименьший набор перекрывающихся заданий
Друг дал мне загадку, которую он говорит, может быть решена лучше, чем O (n ^ 3).
Учитывая набор n заданий, каждый из которых имеет заданное время начала и окончания (перекрытия очень возможны), найдите наименьшее подмножество, которое для каждого задания включает в себя это задание или включает задание, которое перекрывается с этим заданием.
Я уверен, что оптимальным решением является выбор задания с наиболее немаркированным перекрытием, добавление его в набор решений, затем его пометка и совпадение. И повторяйте, пока не будут отмечены все задания.
Выяснение того, какое задание имеет самые немаркированные наложения, представляет собой простую матрицу смежности (O (n ^ 2)), и это нужно переделать каждый раз, когда задание выбрано, чтобы обновить метки, делая его O (n ^ 3).
Есть ли лучшее решение?
Ответы
Ответ 1
Пусть A
- это набор заданий, которые мы еще не перекрывали.
- Найти работу
x
в A
, которая имеет минимальное время окончания (t
).
- От всех заданий, время начала которых меньше
t
: выберите задание j
с максимальным временем окончания.
- Добавьте
j
в выходной набор.
- Удалите все задания, которые перекрывают
j
от A
.
- Повторяйте 1-4 до тех пор, пока
A
не будет пустым.
Простая реализация будет выполняться в O (n ^ 2). Используя интервальные деревья, возможно, это возможно решить в O (n * logn).
Основная идея, почему это оптимальное решение (не формальное доказательство): нам нужно выбрать одно задание, время начала которого меньше t
, так что x
будет перекрываться. Если мы допустим S
множество всех заданий, время начала которых меньше t
, можно показать, что j
будет перекрывать те же задания, что и любое задание в S
, а также, возможно, больше. Поскольку мы должны выбрать одно задание в S
, лучший выбор - j
. Мы можем использовать эту идею, чтобы сформировать доказательство по индукции по количеству заданий.
Ответ 2
Мы можем достичь решения O (nlogn) с подходом к динамическому программированию. В частности, мы хотим рассмотреть размер самого маленького множества, включая задание k th и сопоставление первых заданий k
(упорядоченных по времени начала), которые мы обозначим символом S(k)
. Мы должны сначала добавить вспомогательное задание (∞, ∞), поэтому результатом будет наше решение DP для этого окончательного задания минус единица.
Чтобы вычислить S(k)
, рассмотрите задание p(k)
, которое заканчивается до задания k
, но имеет максимальное время начала. Заметим, что p
является возрастающей функцией. S(k)
будет тогда больше, чем минимум S(i)
с end(i) > start(p(k))
.
Мы можем эффективно найти эту работу, сохранив (S(k)
упорядоченную минимальную) кучу потенциальных заданий. После вычисления каждого S(k)
мы добавляем задание в кучу. Когда мы хотим получить работу, мы удаляем задания у основания кучи, которые заканчиваются слишком рано, пока мы не найдем подходящую. Это займет не более O (nlogn), так как мы выполняем не более O (n) каждой операции кучи (pop/peek/push).
Остальная задача состоит в том, чтобы эффективно вычислить значения p(k)
. Один из способов сделать это - перебрать все начальные и конечные задания (в увеличении времени), отслеживая последнее стартовое задание.