Как Вычесть Ряд Временных Интервалов И Попробовать Алгоритм Бентли-Оттмана

Всем привет! Недавно мне пришлось решить следующую проблему: есть график работы трудовых ресурсов.

Например, график приема врача.

Оно формируется посредством правил и исключений.

Необходимо вычесть исключения из правил, но они периодические и не сразу понятно, в какой момент произойдет пересечение.

И чтобы все это работало быстро, нам пришлось призвать на помощь алгоритмы.

Например: врач Иванова О.

И.

открыт с 8:00 до 14:00 каждый день, кроме выходных.

Но однажды 5 июня 2020 года ей нужно уйти по семейным обстоятельствам с 8:00 до 10:00. Тогда она будет работать в это время на следующей неделе с 15:00 до 17:00. Тогда правила будут выглядеть так: Правила:

1.06.20 8:00 1.06.20 14:00 Периодический 1 день
9.06.20 15:00 9.06.20 17:00 Не периодический
Исключения:
6.06.20 00:00 8.06.20 00:00 Периодический 1 неделя
5.06.20 8:00 5.06.20 10:00 Не периодический
Графически это превращается в такую диаграмму:

Как вычесть ряд временных интервалов и попробовать алгоритм Бентли-Оттмана

Получается, что для получения итогового графика нужно из верхних периодов времени вычесть нижние.

И здесь возможны 4 варианта.

Смотрите картинку ниже:

Как вычесть ряд временных интервалов и попробовать алгоритм Бентли-Оттмана



Ищем решение

Первое решение, которое приходит в голову — сравнить каждое правило с каждым исключением и принять решение: отправлять его в результирующий график или нет. Но сравнение каждого с каждым выглядит как алгоритм сложности O(n 2 ).

Не очень быстро.

Потом я наткнулся на алгоритм Бентли-Оттманн .

В оригинале предполагается найти пересечение прямых на плоскости.

Но у меня случай попроще: отрезки прямой.

Те.

у нас осталось только одно измерение.

Идея оригинального алгоритма Бентли-Оттмана заключается в движущейся строке сканирования, которая регистрирует события начала отрезка и конца отрезка.

А затем сравните вторую координату.

Но в моем случае линия сканирования идет слева направо и просто регистрирует события начала и окончания правил и исключений.

Вот как должен выглядеть результат графически (ниже):

Как вычесть ряд временных интервалов и попробовать алгоритм Бентли-Оттмана



Описание алгоритма

Далее я расскажу, как адаптировать алгоритм Бентли-Оттмана под мою задачу.

1. Начинаем сбор с событий.

Ээлемент коллекции будет выглядеть так

  
  
   

<DateTime, isRule, isOpen>

Тогда наше правило
1.06.20 8:00 1.06.20 14:00 Периодический 1 день
попадает в коллекцию в таком виде:

<1.06.20 8:00, True, True> <1.06.20 14:00,True, False> <2.06.20 8:00, True, True> <2.06.20 14:00, True, False> <3.06.20 8:00, True, True> <3.06.20 14:00, True, False> .



И исключение

6.06.20 00:00 8.06.20 00:00 Периодический 1 неделя
В таком:

<6.06.20 00:00, False, True> <8.06.20 00:00, False, False> <13.06.20 00:00, False, True> <15.06.20 00:00, False, False> .



2. Сортируем нашу коллекцию по первому аргументу DateTime. Это самая затратная часть алгоритма.

Потому что лучшая сложность сортировки — O(n log(n)) В результате мы получаем коллекцию событий, отсортированную по времени: как правил, так и исключений.

В нем содержится информация: когда произошло событие, является ли оно правилом или исключением, а также период открытия или закрытия.

3. Затем используйте цикл foreach для просмотра отсортированной коллекции.

Для каждого элемента коллекции мы примем ряд решений для формулирования результата.

На рисунке ниже показана блок-схема принятия решений.



Как вычесть ряд временных интервалов и попробовать алгоритм Бентли-Оттмана

Комментарии к блок-схеме: isRuleInAction — флаг, который устанавливается в значение True при запуске правила.

Когда правило заканчивается, ему присваивается значение False. isExclusionInAction — флаг, который устанавливается в значение True при возникновении исключения.

Когда исключение заканчивается, ему присваивается значение False. результатКандидат — переменная для хранения кандидата в результирующую коллекцию 4. В результате работы алгоритма получаем коллекцию отсортированных периодов времени.



Заключение

В более абстрактном варианте такой алгоритм можно использовать для пересечения не только временных отрезков, но и обычных отрезков на числовой прямой.

Теги: #Алгоритмы #Bentley-Ottmann

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.