Skip to main content

Техническое задание на разработку Системы планирования и диспетчеризации поставок жидкого цемента «CementFlow»

1. ВВЕДЕНИЕ

1.1. Наименование проекта

Система автоматизированного планирования и диспетчеризации поставок жидкого цемента «CementFlow» с поддержкой каскадного перерасчёта.

1.2. Краткое описание

Разрабатываемая система предназначена для оптимального распределения грузовиков-миксеров для выполнения заказов на доставку жидкого цемента в течение 12-часовой рабочей смены. Система обеспечивает автоматическое планирование поставок, мониторинг исполнения в реальном времени и интеллектуальный перерасчёт расписания при возникновении сбоев (поломки техники, ДТП, задержки).

1.3. Область применения

Система предназначена для использования:

  • Бетонными заводами и производственными комплексами

  • Логистическими компаниями, специализирующимися на перевозке строительных материалов

  • Диспетчерскими службами строительных компаний

1.4. Цели разработки

  1. Повышение эффективности использования парка машин на 25-30%

  2. Снижение простоев грузовиков-миксеров на 35-40%

  3. Минимизация потерь бетона из-за превышения времени жизни

  4. Обеспечение 95% своевременности доставок

  5. Сокращение времени реакции на сбои с 30-60 минут до 5-10 минут

2. ОБЩИЕ ТРЕБОВАНИЯ

2.1. Функциональное назначение

Система должна обеспечивать:

2.1.1. Основные функции:

  1. Планирование смены - формирование оптимального расписания поставок на 12-часовую смену

  2. Распределение грузовиков - автоматический подбор машин для выполнения поставок

  3. Мониторинг исполнения - отслеживание статуса поставок в реальном времени

  4. Каскадный перерасчёт - автоматическое перепланирование при возникновении сбоев

  5. Визуализация - отображение расписания в виде интерактивной диаграммы Ганта

2.1.2. Вспомогательные функции:

  1. Управление справочниками (машины, водители, клиенты, объекты)

  2. Формирование отчётности и аналитика

  3. Интеграция с внешними системами (GPS, ERP, CRM)

  4. Уведомления и оповещения

2.2. Пользователи системы



Роль пользователя Основные функции Доступ
Диспетчер Полный доступ ко всем функциям планирования и мониторинга Веб-интерфейс
Руководитель смены Просмотр, утверждение расписания, анализ эффективности Веб-интерфейс
Водитель Получение заданий, отметка о выполнении этапов, сообщение о проблемах Мобильное приложение
Администратор Управление пользователями, настройка системы, техническая поддержка Веб-интерфейс
Клиент (опционально) Просмотр статуса своего заказа, получение уведомлений Веб-портал/SMS

3. ТЕХНОЛОГИЧЕСКИЕ ТРЕБОВАНИЯ

3.1. Архитектурные требования

  1. Микросервисная архитектура с разделением на независимые модули

  2. Событийно-ориентированная архитектура для обработки событий в реальном времени

  3. REST API для интеграции с внешними системами

  4. Веб-сокеты для обновления интерфейса в реальном времени

  5. Поддержка горизонтального масштабирования

3.2. Технологический стек

Компонент Технологии
Бэкенд .NET 8, C# 12, ASP.NET Core
Фронтенд React 18 + TypeScript, Redux Toolkit/ Svelte SvelteKit + TypeScript
База данных PostgreSQL 16 (основная), Redis 7 (кэш)
Очереди сообщений RabbitMQ или Azure Service Bus
Контейнеризация Docker, Docker Compose
Оркестрация Kubernetes (опционально)
Мониторинг Grafana, Prometheus
CI/CD GitLab CI/CD или GitHub Actions

3.3. Требования к производительности



Параметр Требование
Время отклика API ≤ 200 мс для 95% запросов
Время планирования смены ≤ 30 секунд для 100 заказов
Время каскадного перерасчёта ≤ 10 секунд
Поддержка одновременных пользователей ≥ 50 диспетчеров
Доступность системы 99.5% (SLA)
Время восстановления ≤ 15 минут

4. ДЕТАЛЬНОЕ ОПИСАНИЕ ФУНКЦИОНАЛА

4.1. Модуль управления заказами

4.1.1. Создание и редактирование заказов

  • Форма создания заказа с полями:

    • Клиент (выбор из справочника)

    • Объект доставки (адрес, контактное лицо, телефон)

    • Объём бетона (м³)

    • Марка бетона, подвижность

    • Желаемое время доставки (окно или точное время)

    • Приоритет (нормальный, высокий, критический)

    • Особые требования (непрерывная заливка, бетононасос и т.д.)

4.1.2. Автоматическое разбиение заказов на поставки

  • Алгоритм разбиения учитывает:

    • Вместимость доступных машин

    • Требование непрерывной заливки

    • Оптимальное заполнение миксера (минимизация остатков)

4.2. Модуль планирования

4.2.1. Алгоритм первоначального распределения

Детальное описание приведено в Приложении №1.

Входные данные:

  • Список всех заказов смены

  • Парк доступных машин с характеристиками

  • Расписание работы завода

Этапы алгоритма:

  1. Группировка заказов по приоритету и временным окнам

  2. Разбиение на поставки с учётом непрерывности заливки

  3. Распределение по машинам по критериям:

    • Минимизация порожнего пробега

    • Максимальное использование вместимости

    • Учёт приоритета клиента

  4. Расчёт временных окон с учётом:

    • Времени жизни бетона (90-120 минут)

    • Времени на погрузку, путь, разгрузку, возврат

    • Буфера на форс-мажор (10-15%)

  5. Формирование диаграммы Ганта

4.2.2. Критерии выбора машины

Формула оценки приоритета машины:

Score = (W1 × DistanceScore) + (W2 × CapacityUtilization) + (W3 × TimeWindowFit) + PriorityBonus

где:

  • DistanceScore - оценка расстояния до завода (ближе = лучше)

  • CapacityUtilization - коэффициент заполнения миксера

  • TimeWindowFit - соответствие временному окну клиента

  • PriorityBonus - бонус за приоритет клиента

  • W1, W2, W3 - весовые коэффициенты (настраиваемые)

4.3. Модуль каскадного перерасчёта

4.3.1. Типы обрабатываемых событий

  1. Поломка машины - машина выходит из строя

  2. ДТП - авария с участием машины

  3. Задержка на разгрузке - превышение планового времени разгрузки

  4. Пробки - увеличение времени в пути

  5. Изменение заказа - корректировка клиентом

  6. Новая доступная машина - ввод машины в эксплуатацию

4.3.2. Алгоритм перерасчёта

Детально приведен в Приложении №2.

Шаг 1: Анализ воздействия

  • Определение всех затронутых поставок

  • Оценка степени влияния на график

Шаг 2: Локализация проблемы

  • Ограничение области перерасчёта ближайшими поставками

  • Сохранение неизменными поставок, которые не затрагиваются

Шаг 3: Перераспределение

  • Попытка назначить затронутые поставки другим машинам

  • Использование резервного времени и буферов

  • Приоритизация критических поставок

Шаг 4: Каскадный сдвиг

  • Последовательный сдвиг зависимых поставок

  • Контроль накопления задержек

  • Проверка соблюдения времени жизни бетона

Шаг 5: Эскалация

  • Если автоматическое решение невозможно → уведомление диспетчера

  • Предложение вариантов для ручного выбора

4.4. Модуль визуализации

4.4.1. Диаграмма Ганта

Требования к отображению:

  • По горизонтали - временная шкала смены (12 часов)

  • По вертикали - список машин

  • Для каждой машины - цветные блоки поставок

  • Цветовая индикация статуса:

    • Зелёный - выполняется по плану

    • Жёлтый - есть риски/небольшие отклонения

    • Красный - критические отклонения/просрочки

    • Серый - завершено

Интерактивные возможности:

  • Drag-and-drop для ручного перемещения поставок

  • Масштабирование (часы/минуты)

  • Фильтрация по клиентам, объектам, статусам

  • Подсказки при наведении (детали поставки)

4.4.2. Карта перемещений

  • Отображение местоположения машин в реальном времени

  • Маршруты движения

  • Точки погрузки и разгрузки

  • Пробки и дорожная обстановка (интеграция с картами)

4.5. Модуль интеграций

4.5.1. Внешние системы

Система Тип интеграции Назначение
GPS/телематика REST API/WebSocket Отслеживание местоположения, статуса машин
Картографические сервисы API (Яндекс.Карты/Google Maps) Расчёт маршрутов и времени в пути
ERP система REST API Импорт заказов, экспорт выполненных работ
CRM система REST API Получение информации о клиентах
СМС-сервис REST API Уведомления водителей и клиентов
Погодный сервис REST API Учёт погодных условий в планировании

5. ТРЕБОВАНИЯ К ДАННЫМ

5.1. Структура базы данных

5.1.1. Основные таблицы:

  1. Orders - заказы клиентов

  2. Deliveries - поставки (части заказов)

  3. Trucks - грузовики-миксеры

  4. Drivers - водители

  5. Clients - клиенты

  6. ConstructionSites - объекты строительства

  7. ScheduleSlots - слоты в расписании

  8. Events - события системы

  9. RoutePoints - точки маршрутов

5.1.2. Требования к хранению:

  • История изменений расписания - 90 дней

  • Архив выполненных поставок - 3 года

  • Логи событий - 30 дней

  • Оперативные данные - в кэше Redis

5.2. Форматы данных

5.2.1. JSON API форматы:

{
  "order": {
    "id": "ORD-2024-001",
    "client": {
      "id": "CL-001",
      "name": "ООО СтройГрад",
      "priority": "high"
    },
    "site": {
      "address": "ул. Строителей, 15",
      "coordinates": {"lat": 55.7558, "lng": 37.6176}
    },
    "details": {
      "volume": 15.0,
      "concreteGrade": "M300",
      "slump": 15,
      "requiredWindow": {
        "start": "2024-01-15T09:00:00",
        "end": "2024-01-15T12:00:00"
      },
      "continuousPouring": true,
      "maxInterval": "PT30M"
    }
  }
}

6. ТРЕБОВАНИЯ К ИНТЕРФЕЙСУ

6.1. Веб-интерфейс диспетчера

6.1.1. Основной экран:

  • Левая панель - список заказов с фильтрами

  • Центральная область - диаграмма Ганта

  • Правая панель - детали выбранного элемента, уведомления

  • Верхняя панель - управление сменой, поиск, настройки

6.1.2. Экран планирования:

  • Календарь смен

  • Форма массового планирования

  • Инструменты оптимизации

  • Предпросмотр нагрузки на завод

6.1.3. Экран мониторинга:

  • Карта с движением машин

  • Панель статусов в реальном времени

  • Графики загрузки и эффективности

  • Оповещения о проблемах

6.2. Мобильное приложение водителя

6.2.1. Основные экраны:

  1. Задания на день - список поставок

  2. Текущее задание - детали, карта маршрута

  3. Отметки о выполнении - кнопки для отметки этапов

  4. Сообщения - связь с диспетчером

  5. Проблемы - форма сообщения о сбоях

6.2.2. Функционал:

  • Авторизация по QR-коду или логину

  • Офлайн-работа с последующей синхронизацией

  • GPS-трекинг

  • Фотоотчётность (по требованию)

7. ТРЕБОВАНИЯ К НАДЁЖНОСТИ И БЕЗОПАСНОСТИ

7.1. Надёжность

  • Резервирование всех критических компонентов

  • Автоматическое восстановление после сбоев

  • Ежедневное резервное копирование с хранением 7 дней

  • Мониторинг доступности и производительности

7.2. Безопасность

  • Аутентификация по логину/паролю + 2FA для администраторов

  • Ролевая модель доступа (RBAC)

  • HTTPS для всех соединений

  • Защита от DDoS атак

  • Аудит действий пользователей

  • Шифрование конфиденциальных данных

8. ТРЕБОВАНИЯ К РАЗВЁРТЫВАНИЮ И ЭКСПЛУАТАЦИИ

8.1. Развёртывание

  • Контейнерная поставка всех компонентов

  • Автоматическое развёртывание через CI/CD

  • Документация по установке и настройке

  • Миграционные скрипты для обновлений

8.2. Эксплуатация

  • Техническая поддержка 24/7 для критических инцидентов

  • Обновления - 1 раз в месяц (патчи), 1 раз в квартал (версии)

  • Мониторинг - дашборды, алертинг, логирование

  • Резервное копирование - автоматическое, ежедневно

9. ЭТАПЫ РАЗРАБОТКИ

Этап 1: Прототип и архитектура (1-2 месяца)

  • Разработка архитектуры

  • Создание прототипа алгоритмов планирования

  • Проектирование БД и API

  • Базовый веб-интерфейс

Этап 2: Ядро системы (3-4 месяца)

  • Реализация основных модулей

  • Алгоритмы распределения и перерасчёта

  • Веб-интерфейс диспетчера

  • Интеграция с GPS/картами

Этап 3: Доработка и тестирование (2-3 месяца)

  • Мобильное приложение для водителей

  • Расширенная аналитика

  • Стресс-тестирование

  • Пилотная эксплуатация

Этап 4: Внедрение и поддержка (постоянно)

  • Внедрение у заказчика

  • Обучение пользователей

  • Техническая поддержка

  • Доработки по обратной связи

10. КРИТЕРИИ ПРИЁМКИ

10.1. Функциональные критерии

  1. Система корректно планирует смену для 100+ заказов

  2. Автоматический перерасчёт выполняется за ≤10 секунд

  3. Диаграмма Ганта отображает все поставки без пересечений

  4. Интеграция с GPS работает в реальном времени

  5. Мобильное приложение работает офлайн

10.2. Нефункциональные критерии

  1. Время отклика интерфейса ≤200 мс

  2. Система выдерживает нагрузку 50+ одновременных пользователей

  3. Доступность 99.5% в рабочее время

  4. Данные сохраняются при перезапуске системы

10.3. Приёмочные испытания

  1. Тестирование на тестовых данных - 7 дней

  2. Пилотная эксплуатация - 14 дней

  3. Стресс-тестирование - имитация сбоев и высокой нагрузки

  4. Проверка безопасности - пентест

11. ГАРАНТИИ И ПОДДЕРЖКА

11.1. Гарантийный период

  • 12 месяцев с момента подписания акта приёмки

  • Исправление критических багов - в течение 24 часов

  • Исправление некритических багов - в течение 5 рабочих дней

11.2. Техническая поддержка

  • Поддержка 24/7 для критических инцидентов

  • Консультации по использованию системы

  • Обновления и доработки по согласованию

  • Резервное копирование и восстановление данных

ПРИЛОЖЕНИЯ

Приложение A: Словарь терминов

  • Слот - временной интервал, выделенный машине для выполнения поставки

  • Каскадный перерасчёт - последовательное перепланирование зависимых поставок

  • Время жизни бетона - период от замеса до начала схватывания (90-120 минут)

  • Непрерывная заливка - требование минимального интервала между поставками на объект

Приложение B: Схемы интеграций

(Диаграммы последовательности и архитектурные схемы)

Приложение C: Макеты интерфейсов

(Визуальные макеты всех экранов системы)


ИСПОЛНИТЕЛЬ: [Наименование организации-исполнителя]

ЗАКАЗЧИК: [Наименование организации-заказчика]

СРОК РАЗРАБОТКИ: 8-12 месяцев

СТОИМОСТЬ РАЗРАБОТКИ: [Сумма] руб.

СРОК ДЕЙСТВИЯ ТЗ: до [Дата]


Документ утверждён:
[Подпись Заказчика] [Подпись Исполнителя]
[Дата] [Дата]


Приложение №1

ДЕТАЛЬНОЕ ОПИСАНИЕ АЛГОРИТМА ПЕРВОНАЧАЛЬНОГО РАСПРЕДЕЛЕНИЯ

1. ОБЩИЙ ПРИНЦИП РАБОТЫ АЛГОРИТМА

Алгоритм первоначального распределения — это многоуровневая жадная эвристика с обратной связью, которая преобразует список заказов клиентов в оптимизированное расписание поставок для всего парка машин на 12-часовую смену. Алгоритм работает по принципу "наиболее ограниченные задачи решаются первыми".

Ключевая идея: Сначала назначаются самые сложные и критичные поставки, затем менее сложные, что позволяет избежать ситуаций, когда критичные задачи невозможно выполнить из-за того, что все ресурсы уже заняты менее важными задачами.

2. ПОШАГОВЫЙ АЛГОРИТМ С РАСЧЁТАМИ

Этап 0: Подготовка данных (Pre-processing)

Входные данные:

  • Список заказов на смену (N заказов)

  • Парк доступных машин (M единиц)

  • Параметры смены (начало T_start, конец T_end, координаты завода)

  • Технологические константы (время погрузки, средняя скорость и т.д.)

Шаг 0.1: Валидация и нормализация данных


Для каждого заказа:
  1. Проверить корректность данных
  2. Рассчитать минимальное и максимальное время доставки
  3. Привести желаемое окно клиента к стандартному формату
  4. Вычислить коэффициент срочности = (дедлайн - текущее время) / общее время смены

Шаг 0.2: Сортировка заказов по сложности выполнения


Сложность_заказа = (Приоритет_клиента × 0.4) + 
                   (Коэффициент_срочности × 0.3) + 
                   (Объём_заказа / Стандартный_объём × 0.2) + 
                   (Сложность_логистики × 0.1)
                   
Сортируем заказы по убыванию Сложности_заказа

Этап 1: Разбиение заказов на атомарные поставки

Шаг 1.1: Определение оптимального размера поставки


Для каждого заказа:
  Если Объём_заказа ≤ Максимальная_вместимость_машины:
    Количество_поставок = 1
    Объём_поставки = Объём_заказа
  Иначе:
    Найти все доступные вместимости машин: C1, C2, ..., Ck
    Найти оптимальное разбиение, минимизирующее:
      Целевая_функция = α × Количество_поставок + 
                        β × (Сумма_остатков_в_машинах) + 
                        γ × (Максимальный_интервал_между_поставками)

Пример расчёта для заказа 15 м³:


Доступные вместимости машин: 5 м³, 7 м³, 10 м³
Варианты разбиения:
  1) 3 × 5 м³ = 15 м³ (остаток 0) ✓
  2) 2 × 7 м³ = 14 м³ (остаток 1 м³ - требует доп. машину 5 м³)
  3) 1 × 10 м³ + 1 × 5 м³ = 15 м³ (остаток 0) ✓
  
Выбираем вариант 3, так как минимизирует количество поставок

Шаг 1.2: Создание сущностей поставок


Для каждой поставки:
  1. Присвоить уникальный ID
  2. Унаследовать данные от родительского заказа
  3. Рассчитать параметры:
     - Минимальное время выполнения = Погрузка + Путь_туда + Разгрузка + Возврат
     - Время жизни бетона = 90 минут (для стандартного бетона)
     - Окончательный дедлайн = MIN(Дедлайн_клиента, Время_начала + Время_жизни)

Этап 2: Группировка поставок для параллельной обработки

Шаг 2.1: Создание групп по ограничениям


Группа А: Поставки с жёсткими временными окнами (нельзя сдвигать)
Группа Б: Поставки, требующие непрерывной заливки
Группа В: Поставки для VIP-клиентов
Группа Г: Стандартные поставки
Группа Д: Поставки с гибкими временами

Приоритет обработки: А → Б → В → Г → Д

Шаг 2.2: Внутригрупповая сортировка


Для каждой группы сортировка по:
  1. Времени начала окна (от более раннего к более позднему)
  2. Длительности окна (от более узкого к более широкому)
  3. Объёму (от большего к меньшему)

Этап 3: Распределение поставок по машинам

Цикл обработки поставок:


Для каждой поставки в порядке приоритета групп:
  Шаг 3.1: Формирование пула кандидатов
    Для каждой машины проверяем:
      1. Вместимость ≥ Объём_поставки
      2. Техническая исправность = true
      3. Машина доступна в течение смены
      4. Машина может прибыть на завод к нужному времени
      
  Шаг 3.2: Предварительная оценка кандидатов
    Для каждой машины-кандидата рассчитываем:
      Время_начала_минимальное = MAX(Текущее_свободное_время, Время_прибытия_на_завод)
      Время_окончания = Время_начала + Длительность_поставки
      
    Отсеиваем кандидатов, у которых:
      - Время_окончания > Окончательный_дедлайн
      - Время_окончания > Конец_смены
      - Время_разгрузки > Время_начала + Время_жизни_бетона
      
  Шаг 3.3: Детальный расчёт для каждого кандидата
    Для каждого оставшегося кандидата:
      1. Рассчитать точное время всех этапов:
         - Выезд на завод: Время_начала - Путь_до_завода
         - Погрузка: 15-20 минут (зависит от объёма)
         - Путь к клиенту: Расстояние / Средняя_скорость × Коэффициент_пробок
         - Разгрузка: 2-3 минуты на м³
         - Возврат: Расстояние_обратно / Средняя_скорость
         
      2. Проверить пересечения с существующими слотами машины
      3. Рассчитать буферы:
         - Операционный буфер: 10% от времени в пути
         - Рисковый буфер: 5-15 минут (зависит от сложности объекта)
         
  Шаг 3.4: Оценка и выбор лучшего кандидата
    Оценочная_функция(Машина, Поставка) = 
      W1 × Оценка_времени + 
      W2 × Оценка_расстояния + 
      W3 × Оценка_использования + 
      W4 × Оценка_качества
    
    Где:
      Оценка_времени = 1 / (Время_начала - Идеальное_время_начала)²
      Оценка_расстояния = 1 / (Порожний_пробег + 1)
      Оценка_использования = Объём_поставки / Вместимость_машины
      Оценка_качества = Коэффициент_приоритета_клиента
      
    W1, W2, W3, W4 — настраиваемые веса (по умолчанию: 0.4, 0.3, 0.2, 0.1)
    
  Шаг 3.5: Назначение и фиксация
    Если найден подходящий кандидат:
      - Закрепляем поставку за машиной
      - Создаём слот с рассчитанными временами
      - Обновляем доступное время машины
      - Добавляем в расписание
    Иначе:
      - Перемещаем поставку в очередь проблемных
      - Записываем причину неудачи

Этап 4: Обработка поставок, требующих непрерывной заливки

Особый алгоритм для заказов с непрерывной заливкой:


Для каждого заказа с требованием непрерывности:
  1. Собрать все поставки этого заказа в группу
  2. Определить требуемый интервал между поставками (например, ≤30 минут)
  3. Найти машины, которые могут выполнить несколько поставок подряд:
     - Проверить возможность выполнения N поставок одной машиной
     - Рассчитать суммарное время и проверить попадание в окно клиента
     
  4. Если одной машиной невозможно:
     - Найти несколько машин с максимально близкими временами разгрузки
     - Синхронизировать их расписание для минимизации интервалов
     
  5. Провести корректировку:
     - Сдвинуть поставки для соблюдения интервала
     - Убедиться, что сдвиг не нарушает другие ограничения

Этап 5: Пост-обработка и оптимизация

Шаг 5.1: Балансировка нагрузки

text
Для каждой машины рассчитываем:
  Коэффициент_загрузки = Суммарное_время_работы / Длительность_смены
  
Средний_коэффициент = SUM(Коэффициент_загрузки) / Количество_машин

Для машин с Коэффициент_загрузки > Средний_коэффициент + 0.2:
  Попробовать перенести часть поставок на менее загруженные машины

Шаг 5.2: Минимизация порожних пробегов


Для каждой последовательности поставок у машины:
  Рассчитать маршрут: База → Завод → Объект1 → Завод → Объект2 → ...
  Оценить порожний пробег между объектами
  
Попробовать переставить поставки в последовательности для:
  - Уменьшения расстояния между объектами
  - Группировки поставок по географическим зонам

Шаг 5.3: Добавление защитных буферов


Для каждого слота в расписании:
  Если поставка критичная или объект сложный:
    Добавить_буфер = 15-20 минут
  Иначе если время в пути > 60 минут:
    Добавить_буфер = 10% от времени в пути
  Иначе:
    Добавить_буфер = 5 минут
    
Распределить буфер:
  - 50% добавить перед разгрузкой (на случай задержек в пути)
  - 50% добавить после разгрузки (на случай задержек на объекте)

Этап 6: Обработка проблемных поставок

Шаг 6.1: Анализ причин неудачи


Типичные причины:
  1. Нехватка машин нужной вместимости
  2. Отсутствие временных окон
  3. Противоречивые ограничения
  4. Невозможность соблюсти время жизни бетона

Шаг 6.2: Попытка перераспределения


Для каждой проблемной поставки:
  1. Ослабить ограничения (если возможно):
     - Расширить временное окно
     - Разрешить использование машин большей вместимости
     - Увеличить максимальный интервал для непрерывной заливки
     
  2. Попробовать занять резервное время других машин
  3. Предложить разбить поставку на меньшие части

Шаг 6.3: Эскалация к диспетчеру

text
Если автоматическое распределение невозможно:
  1. Сформировать отчёт с причинами
  2. Предложить варианты решения:
     - Добавить дополнительную машину
     - Перенести заказ на другую смену
     - Увеличить временное окно
     - Изменить параметры заказа
     
  3. Передать задачу диспетчеру для ручного решения

3. МАТЕМАТИЧЕСКАЯ ФОРМАЛИЗАЦИЯ

Основная целевая функция:


Минимизировать: Z = α×Z₁ + β×Z₂ + γ×Z₃ + δ×Z₄

Где:
  Z₁ = Σ(Время_доставки - Идеальное_время)²  # Минимизация отклонений
  Z₂ = Σ(Порожний_пробег)                    # Минимизация пробегов
  Z₃ = Σ(1 - Коэффициент_заполнения)²        # Максимизация использования
  Z₄ = Σ(Штрафы_за_нарушение_ограничений)    # Минимизация нарушений

Ограничения:


1. ∀i: Время_начала_слота_i ≥ Время_окончания_слота_{i-1} + Время_перехода
2. ∀i: Время_разгрузки_i ≤ Время_погрузки_i + Время_жизни_бетона
3. ∀j: Σ(Объём_поставок_заказа_j) = Объём_заказа_j
4. ∀k: Σ(Время_работы_машины_k) ≤ Длительность_смены
5. ∀l,m: |Время_разгрузки_l - Время_разгрузки_m| ≤ Максимальный_интервал, 
   если l и m принадлежат одному заказу с непрерывной заливкой

4. ПРИМЕР РАСЧЁТА ДЛЯ КОНКРЕТНОГО СЦЕНАРИЯ

Исходные данные:

  • Смена: 07:00 - 19:00 (12 часов)

  • Парк: 5 машин (вместимости: 5, 5, 7, 7, 10 м³)

  • Завод: Координаты (55.7558, 37.6176)

  • Средняя скорость: 40 км/ч в городе, 60 км/ч за городом

Заказ 1:

  • Клиент: СтройГрад (приоритет: высокий)

  • Объём: 15 м³

  • Объект: 10 км от завода

  • Окно: 09:00 - 12:00

  • Требуется непрерывная заливка, макс. интервал 30 мин

Расчёт алгоритма:

Шаг 1: Разбиение заказа


Оптимальное разбиение: 10 м³ + 5 м³
Обоснование: Минимизация количества поставок (2 вместо 3)

Шаг 2: Расчёт временных параметров для поставки 10 м³


Время погрузки: 10 м³ × 3 мин/м³ = 30 минут
Время в пути: 10 км / 40 км/ч = 15 минут
Время разгрузки: 10 м³ × 2.5 мин/м³ = 25 минут
Возврат: 10 км / 40 км/ч = 15 минут
Итого: 30 + 15 + 25 + 15 = 85 минут
Буфер: 10% = 9 минут
Общее время слота: 94 минуты ≈ 1 час 34 минуты

Шаг 3: Поиск подходящей машины


Кандидаты по вместимости: машины 7 м³ и 10 м³
Машина 1 (7 м³): не подходит - объём 10 > 7
Машина 2 (7 м³): не подходит
Машина 3 (10 м³): свободна с 07:00

Расчёт для машины 3:
  Выезд с базы: 07:00
  Прибытие на завод: 07:15
  Погрузка: 07:15 - 07:45
  Путь к клиенту: 07:45 - 08:00
  Разгрузка: 08:00 - 08:25
  Возврат: 08:25 - 08:40
  
Проверка ограничений:
  ✓ Попадание в окно клиента (08:00 ∈ [09:00-12:00] - требуется корректировка)
  ✓ Время жизни бетона: 08:00 - 07:45 = 15 минут < 90 минут
  ✓ Конец слота 08:40 < конец смены 19:00

Шаг 4: Корректировка времени


Требуется сдвинуть на 1 час позже:
  Погрузка: 08:15 - 08:45
  Разгрузка: 09:00 - 09:25 (попадает в окно)
  
Обновлённый слот: 08:00 - 09:40

Шаг 5: Аналогичный расчёт для поставки 5 м³


Выбираем машину 5 м³, начинаем на 30 минут позже первой поставки
для соблюдения непрерывной заливки:
  Разгрузка: 09:25 - 09:40 (интервал 0 минут ✓)

5. ОСОБЕННОСТИ РЕАЛИЗАЦИИ

5.1. Эвристические правила, используемые в алгоритме:

  1. Правило ближайшего соседа:

    • После выполнения поставки на объекте, следующая поставка назначается на ближайший объект

  2. Правило заполнения до конца:

    • Если осталось мало времени до конца смены, назначаются короткие поставки рядом с базой

  3. Правило резервирования VIP:

    • Для VIP-клиентов резервируется 10% времени у лучших машин

  4. Правило избегания пиков:

    • Стараться не назначать разгрузку в часы пик (08:00-10:00, 17:00-19:00)

5.2. Обработка конфликтов и тупиковых ситуаций:

Тупиковая ситуация: Нельзя назначить поставку без нарушения ограничений

Стратегии выхода:

  1. Откат (Backtracking): Отменить последнее назначение и попробовать другой вариант

  2. Ослабление ограничений: Временно разрешить небольшое нарушение

  3. Разделение проблемы: Разделить сложную поставку на части

  4. Перенос на потом: Отложить решение до обработки других поставок

5.3. Оптимизационные улучшения:

  1. Локальный поиск: После построения расписания пытаться улучшить его небольшими изменениями

  2. Табу-поиск: Запрещать возврат к недавно рассмотренным решениям

  3. Имитация отжига: Иногда разрешать ухудшения для выхода из локальных оптимумов

6. ПРОИЗВОДИТЕЛЬНОСТЬ И МАСШТАБИРУЕМОСТЬ

Временная сложность:


O(N × M × K × L)
Где:
  N - количество поставок
  M - количество машин
  K - среднее количество временных окон у машины
  L - сложность проверки ограничений

Для типичного сценария (50 поставок, 10 машин):
  ≈ 50 × 10 × 5 × 10 = 25,000 операций
  Время выполнения: ~2-3 секунды

Память:


Требуется хранить:
  - Матрицу назначений: N × M элементов
  - Расписание каждой машины: M списков по ~10 элементов
  - Кэш рассчитанных расстояний: ~N² элементов
  
Общий объём: O(N² + M × N) ≈ 100-500 КБ для типичного сценария

7. ВАЛИДАЦИЯ И ТЕСТИРОВАНИЕ АЛГОРИТМА

Тестовые сценарии:

  1. Идеальный случай: Все поставки могут быть назначены без конфликтов

  2. Предельная загрузка: Количество поставок на пределе возможностей парка

  3. Конфликт ограничений: Противоречивые требования клиентов

  4. Каскадный сбой: Отказ ключевой машины в начале смены

Метрики качества расписания:

text
1. Коэффициент использования машин: Должен быть 70-90%
2. Среднее отклонение от идеального времени: Должно быть < 30 минут
3. Количество нарушений ограничений: Должно быть 0
4. Суммарный порожний пробег: Минимизируется
5. Баланс загрузки: Разница загрузки машин < 20%

8. ИНТЕГРАЦИЯ С ДРУГИМИ СИСТЕМАМИ

Алгоритм получает данные из:

  1. CRM-системы — информация о клиентах и их приоритетах

  2. ERP-системы — данные о заказах и производственных мощностях

  3. GPS-трекера — текущее положение машин

  4. Картографических сервисов — актуальные данные о пробках и маршрутах

  5. Погодных сервисов — прогноз для корректировки времени в пути

9. НАСТРОЙКА И КАЛИБРОВКА

Алгоритм имеет настраиваемые параметры:

python
# Веса в оценочной функции
WEIGHTS = {
    'time_deviation': 0.4,      # Важность соблюдения времени
    'distance': 0.3,            # Важность минимизации пробега
    'capacity_utilization': 0.2, # Важность заполнения машины
    'client_priority': 0.1      # Важность приоритета клиента
}

# Буферы и допуски
TOLERANCES = {
    'time_window': 15,          # Допустимое отклонение от окна (мин)
    'continuous_pouring': 5,    # Допуск по интервалу непрерывности (мин)
    'concrete_lifetime': 10     # Запас по времени жизни бетона (мин)
}

# Стратегические параметры
STRATEGY = {
    'reserve_vip_capacity': 0.1, # Резерв для VIP-клиентов (10%)
    'max_backtracking_depth': 3, # Макс. глубина отката
    'optimization_iterations': 100 # Количество итераций оптимизации
}

10. ПРАКТИЧЕСКИЕ РЕКОМЕНДАЦИИ ПО РЕАЛИЗАЦИИ

  1. Начинать с простого: Сначала реализовать базовый жадный алгоритм без оптимизации

  2. Добавлять сложность постепенно: Поэтапно вводить дополнительные ограничения и оптимизации

  3. Использовать кэширование: Кэшировать результаты расчёта расстояний и проверок

  4. Реализовать инкрементальное обновление: При изменении одной поставки не пересчитывать всё расписание

  5. Предусмотреть ручное вмешательство: Возможность диспетчера корректировать автоматические решения

ЗАКЛЮЧЕНИЕ

Алгоритм первоначального распределения представляет собой сбалансированную комбинацию эвристических правил и оптимизационных техник, которая позволяет быстро строить качественное расписание даже для сложных сценариев. Его ключевые преимущества:

  1. Гарантированное нахождение решения (если оно существует)

  2. Учёт всех технологических ограничений цементной логистики

  3. Баланс между оптимальностью и скоростью работы

  4. Возможность каскадной обработки — сначала сложные, потом простые задачи

  5. Интеграция с системами реального времени для учёта текущей обстановки

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


 

Приложение №2

 

ДЕТАЛЬНОЕ ОПИСАНИЕ АЛГОРИТМА КАСКАДНОГО ПЕРЕРАСЧЕТА

1. ФИЛОСОФИЯ АЛГОРИТМА: УПРАВЛЕНИЕ ХАОСОМ В РЕАЛЬНОМ ВРЕМЕНИ

Алгоритм каскадного перерасчёта — это интеллектуальная система экстренного реагирования, которая превращает хаотичные сбои в управляемые изменения расписания. Он работает по принципу "минимального необходимого вмешательства" — как хирург, который делает точечные разрезы, а не ампутирует конечности.

Ментальная модель: Представьте домино. Одно падающее костяшка (сбой) может уронить всю цепь (расписание). Наш алгоритм — это рука, которая подхватывает упавшие костяшки и расставляет их на новые места, не давая упасть остальным.

2. КЛАССИФИКАЦИЯ СОБЫТИЙ И СТРАТЕГИИ РЕАКЦИИ

2.1. Матрица событий и их каскадных эффектов:



Событие Непосредственный эффект Каскадный эффект Время реакции Приоритет обработки
Полный отказ машины Машина выбывает до конца смены Все будущие слоты освобождаются 0-2 минуты Критический (1)
Частичная поломка Машина встанет на 2-4 часа Слоты в периоде простоя сдвигаются 2-5 минут Высокий (2)
ДТП без пострадавших Машина задержана на 1-3 часа Текущая поставка отменяется, следующие сдвигаются 5-10 минут Высокий (2)
Задержка на разгрузке Текущий слот удлиняется на X минут Последующие слоты этой машины сдвигаются 1-3 минуты Средний (3)
Пробки на маршруте Увеличение времени в пути на Y% Риск превышения времени жизни бетона 2-5 минут Средний (3)
Отмена заказа клиентом Освобождается N слотов Появляется резерв для других поставок 1-2 минуты Низкий (4)
Новая доступная машина Увеличивается мощность парка Возможность оптимизации нагрузки 3-7 минут Низкий (4)

2.2. Жизненный цикл обработки события:

text
1. ДЕТЕКЦИЯ (0-30 секунд)
   │
2. ВАЛИДАЦИЯ (30-60 секунд)
   │
3. ОЦЕНКА ВОЗДЕЙСТВИЯ (60-90 секунд)
   │
4. РАЗРАБОТКА СТРАТЕГИИ (90-120 секунд)
   │
5. ВЫПОЛНЕНИЕ ПЕРЕРАСЧЕТА (120-300 секунд)
   │
6. ВАЛИДАЦИЯ РЕЗУЛЬТАТА (300-360 секунд)
   │
7. УВЕДОМЛЕНИЕ СТОРОН (360-420 секунд)

3. ДЕТАЛЬНЫЙ АЛГОРИТМ ДЛЯ КРИТИЧЕСКОГО СОБЫТИЯ: ПОЛНАЯ ПОЛОМКА МАШИНЫ

ФАЗА 1: ЭКСПРЕСС-ДИАГНОСТИКА (0-60 секунд)

python
def emergency_assessment(event):
    """
    Молниеносная оценка ситуации
    """
    # Шаг 1.1: Определение точки невозврата
    breakdown_time = event.occurred_at
    truck = event.related_truck
    
    # Какие поставки УЖЕ НЕВОЗМОЖНО выполнить
    immediate_impact = []
    for slot in truck.schedule:
        if slot.start_time <= breakdown_time <= slot.end_time:
            # Текущая поставка - экстренная ситуация
            current_delivery = slot.delivery
            if current_delivery.is_in_transit():
                # Бетон уже в пути - критично!
                cement_age = breakdown_time - current_delivery.mixing_start_time
                remaining_lifetime = current_delivery.concrete_lifetime - cement_age
                
                if remaining_lifetime < TimeSpan.FromMinutes(30):
                    # Бетон скоро схватится - нужна срочная замена
                    immediate_impact.append({
                        'delivery': current_delivery,
                        'type': 'CRITICAL_CEMENT_AT_RISK',
                        'remaining_minutes': remaining_lifetime.total_minutes,
                        'required_action': 'IMMEDIATE_REASSIGNMENT'
                    })
    
    # Шаг 1.2: Быстрая инвентаризация ресурсов
    available_trucks = get_available_trucks(
        from_time=breakdown_time,
        min_capacity=5,  # минимальная вместимость
        proximity_to_plant=True
    )
    
    # Шаг 1.3: Расчет окна возможностей
    opportunity_window = calculate_opportunity_window(
        broken_truck=truck,
        available_trucks=available_trucks,
        time_now=breakdown_time
    )
    
    return {
        'immediate_crises': immediate_impact,
        'available_resources': available_trucks,
        'window_of_opportunity': opportunity_window,
        'severity_level': calculate_severity(immediate_impact)
    }

ФАЗА 2: СТРАТЕГИЧЕСКОЕ ПЛАНИРОВАНИЕ (60-120 секунд)

python
def develop_rescue_strategy(assessment):
    """
    Разработка многоуровневой стратегии спасения
    """
    strategy = {
        'phase_1': [],  # Действия в ближайшие 15 минут
        'phase_2': [],  # Действия в ближайший час
        'phase_3': [],  # Действия на оставшуюся смену
        'fallback_plans': []  # Резервные варианты
    }
    
    # УРОВЕНЬ 1: Спасение бетона, который уже в пути
    for crisis in assessment['immediate_crises']:
        if crisis['type'] == 'CRITICAL_CEMENT_AT_RISK':
            rescue_plan = create_cement_rescue_plan(
                delivery=crisis['delivery'],
                time_limit=crisis['remaining_minutes'],
                available_trucks=assessment['available_resources']
            )
            
            if rescue_plan['feasible']:
                strategy['phase_1'].append({
                    'action': 'EMERGENCY_TRANSFER',
                    'plan': rescue_plan,
                    'priority': 'CRITICAL'
                })
            else:
                # Невозможно спасти - план минимизации убытков
                strategy['phase_1'].append({
                    'action': 'DAMAGE_CONTROL',
                    'plan': create_damage_control_plan(crisis['delivery']),
                    'priority': 'CRITICAL'
                })
    
    # УРОВЕНЬ 2: Перераспределение ближайших поставок (15-60 минут)
    immediate_slots = get_immediate_slots(
        truck=assessment['broken_truck'],
        time_horizon=TimeSpan.FromHours(2),
        from_time=assessment['breakdown_time']
    )
    
    for slot in immediate_slots:
        reassignment_plan = create_slot_reassignment_plan(
            slot=slot,
            available_trucks=assessment['available_resources'],
            strategy='NEAREST_FIT'
        )
        
        strategy['phase_2'].append({
            'action': 'SLOT_REASSIGNMENT',
            'slot': slot,
            'plan': reassignment_plan,
            'priority': 'HIGH' if slot.delivery.client.priority >= 8 else 'MEDIUM'
        })
    
    # УРОВЕНЬ 3: Оптимизация оставшейся смены
    remaining_slots = get_remaining_slots(
        truck=assessment['broken_truck'],
        from_time=assessment['breakdown_time'] + TimeSpan.FromHours(2)
    )
    
    optimization_strategy = create_optimization_strategy(
        slots=remaining_slots,
        available_trucks=assessment['available_resources'],
        time_constraints=assessment['window_of_opportunity']
    )
    
    strategy['phase_3'] = optimization_strategy
    
    # Резервные планы
    strategy['fallback_plans'] = create_fallback_plans(strategy)
    
    return strategy

ФАЗА 3: КАСКАДНЫЙ ПЕРЕРАСЧЕТ С УПРАВЛЯЕМЫМ РАСПРОСТРАНЕНИЕМ

python
def execute_cascade_reschedule(strategy, original_schedule):
    """
    Выполнение каскадного перерасчета с контролем распространения
    """
    # Шаг 3.1: Создание "песочницы" для экспериментов
    sandbox_schedule = original_schedule.clone()
    change_log = []
    
    # Шаг 3.2: Последовательное выполнение фаз стратегии
    for phase_name in ['phase_1', 'phase_2', 'phase_3']:
        phase_actions = strategy[phase_name]
        
        for action in phase_actions:
            result = execute_action_in_sandbox(
                action=action,
                schedule=sandbox_schedule,
                change_log=change_log
            )
            
            if not result['success']:
                # Действие не удалось - активируем механизм компенсации
                compensation = create_compensation_plan(
                    failed_action=action,
                    failure_reason=result['reason'],
                    current_state=sandbox_schedule
                )
                
                # Пытаемся выполнить компенсацию
                compensation_result = execute_compensation(
                    compensation_plan=compensation,
                    schedule=sandbox_schedule
                )
                
                if not compensation_result['success']:
                    # Каскадная неудача - эскалация
                    escalate_to_human(
                        action=action,
                        compensation=compensation,
                        current_state=sandbox_schedule
                    )
    
    # Шаг 3.3: Проверка целостности нового расписания
    integrity_check = validate_schedule_integrity(sandbox_schedule)
    
    if integrity_check['valid']:
        # Шаг 3.4: Постепенное применение изменений
        final_schedule = apply_changes_gradually(
            original=original_schedule,
            new=sandbox_schedule,
            change_log=change_log
        )
        
        return {
            'success': True,
            'schedule': final_schedule,
            'changes_made': len(change_log),
            'cascade_depth': calculate_cascade_depth(change_log),
            'estimated_impact': calculate_impact_metrics(change_log)
        }
    else:
        # Не удалось построить валидное расписание
        return {
            'success': False,
            'reason': integrity_check['violations'],
            'fallback_activated': True
        }

4. АЛГОРИТМ ПЕРЕРАСЧЕТА ПРИ ЗАДЕРЖКЕ НА РАЗГРУЗКЕ

Специфика: Задержка вызывает цепную реакцию, но не требует смены машины.

python
def handle_unloading_delay(event):
    """
    Обработка задержки на разгрузке с минимизацией каскадного эффекта
    """
    # Шаг 1: Точное измерение задержки
    delay = event.delay_minutes
    affected_slot = event.related_slot
    truck = affected_slot.truck
    
    # Шаг 2: Анализ "эластичности" временных окон
    elasticity_analysis = analyze_time_elasticity(
        slot=affected_slot,
        requested_delay=delay
    )
    
    # Шаг 3: Многоуровневая стратегия поглощения задержки
    
    # Уровень 1: Поглощение за счет внутренних резервов
    if elasticity_analysis['can_absorb_without_shift']:
        # Задержку можно поглотить за счет буферов
        adjusted_schedule = absorb_delay_internally(
            schedule=current_schedule,
            slot=affected_slot,
            delay=delay
        )
        
    # Уровень 2: Минимальный сдвиг с компенсацией
    elif elasticity_analysis['can_shift_with_minimal_impact']:
        # Находим оптимальную точку сдвига
        shift_point = find_optimal_shift_point(
            truck_schedule=truck.schedule,
            delayed_slot=affected_slot,
            delay=delay
        )
        
        # Выполняем "умный" сдвиг
        adjusted_schedule = execute_smart_shift(
            schedule=current_schedule,
            shift_from=shift_point,
            shift_amount=delay,
            strategy='MINIMAL_DISTURBANCE'
        )
        
    # Уровень 3: Каскадный перерасчет с изоляцией
    else:
        # Изолируем область воздействия
        impact_zone = isolate_impact_zone(
            schedule=current_schedule,
            epicenter=affected_slot,
            max_ripple_hours=2  # Ограничиваем распространение 2 часами
        )
        
        # Перераспределяем в изолированной зоне
        adjusted_schedule = reschedule_within_zone(
            schedule=current_schedule,
            impact_zone=impact_zone,
            delay_source=affected_slot
        )
    
    # Шаг 4: Проверка и компенсация
    compensation_needed = check_for_compensation_needs(adjusted_schedule)
    
    if compensation_needed:
        adjusted_schedule = apply_compensation_measures(
            schedule=adjusted_schedule,
            compensation_plan=compensation_needed
        )
    
    return adjusted_schedule

5. ИНТЕЛЛЕКТУАЛЬНЫЙ МЕХАНИЗМ ПРЕДОТВРАЩЕНИЯ КАСКАДНЫХ СБОЕВ

5.1. Алгоритм "Умной изоляции":

python
def intelligent_impact_isolation(schedule, failure_point):
    """
    Изоляция области воздействия сбытия с минимизацией распространения
    """
    # Шаг 1: Определение "эпицентра" и "эпицентральной зоны"
    epicenter = failure_point
    epicentral_zone = calculate_epicentral_zone(
        epicenter=epicenter,
        radius_hours=1,  # Первый час - максимальное воздействие
        schedule=schedule
    )
    
    # Шаг 2: Идентификация "амортизаторов" - поставок, которые могут сдвинуться без последствий
    shock_absorbers = identify_shock_absorbers(
        schedule=schedule,
        around_zone=epicentral_zone,
        buffer_size=2  # 2 слота в каждую сторону
    )
    
    # Шаг 3: Создание "защитного периметра"
    protective_perimeter = create_protective_perimeter(
        schedule=schedule,
        inner_zone=epicentral_zone,
        outer_radius_hours=3
    )
    
    # Шаг 4: Расчет "коэффициента упругости" для каждого слота
    elasticity_map = calculate_slot_elasticity(
        schedule=schedule,
        zone=epicentral_zone + protective_perimeter
    )
    
    return {
        'epicenter': epicenter,
        'epicentral_zone': epicentral_zone,
        'shock_absorbers': shock_absorbers,
        'protective_perimeter': protective_perimeter,
        'elasticity_map': elasticity_map,
        'isolation_strategy': 'ADAPTIVE_CONTAINMENT'
    }

5.2. Алгоритм "Приоритетного спасения":

python
def priority_based_rescue(schedule, affected_slots):
    """
    Спасение поставок по приоритету с учетом многомерных критериев
    """
    # Многомерная оценка критичности каждой поставки
    criticality_scores = []
    
    for slot in affected_slots:
        score = calculate_multidimensional_criticality(
            slot=slot,
            dimensions=[
                'CLIENT_PRIORITY',      # Важность клиента
                'CEMENT_VIABILITY',     # Риск схватывания бетона
                'CONTRACT_PENALTY',     # Штрафы за срыв
                'LOGISTIC_COMPLEXITY',  # Сложность замены
                'IMPACT_ON_OTHERS'      # Влияние на другие поставки
            ]
        )
        
        criticality_scores.append({
            'slot': slot,
            'score': score,
            'rescue_window': calculate_rescue_window(slot),
            'rescue_options': find_rescue_options(slot, schedule)
        })
    
    # Сортировка по критичности и доступности вариантов спасения
    criticality_scores.sort(
        key=lambda x: (
            -x['score']['overall'],  # По убыванию критичности
            len(x['rescue_options']),  # По количеству вариантов
            x['rescue_window']['minutes_remaining']  # По оставшемуся времени
        )
    )
    
    # Последовательное спасение
    rescued_slots = []
    failed_rescues = []
    
    for item in criticality_scores:
        rescue_result = attempt_slot_rescue(
            slot=item['slot'],
            options=item['rescue_options'],
            schedule=schedule,
            time_limit=item['rescue_window']['minutes_remaining']
        )
        
        if rescue_result['success']:
            rescued_slots.append({
                'slot': item['slot'],
                'new_assignment': rescue_result['new_assignment']
            })
            schedule = rescue_result['updated_schedule']
        else:
            failed_rescues.append({
                'slot': item['slot'],
                'reason': rescue_result['failure_reason'],
                'suggested_actions': rescue_result['suggestions']
            })
    
    return {
        'rescued_count': len(rescued_slots),
        'failed_count': len(failed_rescues),
        'rescued_slots': rescued_slots,
        'failed_rescues': failed_rescues,
        'final_schedule': schedule,
        'rescue_efficiency': len(rescued_slots) / len(affected_slots)
    }

6. АЛГОРИТМ ОБРАБОТКИ МНОЖЕСТВЕННЫХ СБОЕВ

Сценарий: Одновременная поломка 2 машин + задержка на 3 объектах

python
def handle_multiple_failures(failure_events):
    """
    Обработка множественных одновременных сбоев
    """
    # Шаг 1: Кластеризация сбоев по времени и местоположению
    failure_clusters = cluster_failures(
        events=failure_events,
        time_threshold=TimeSpan.FromMinutes(30),
        location_threshold=5  # км
    )
    
    # Шаг 2: Определение доминирующего сбоя в каждом кластере
    dominant_failures = []
    for cluster in failure_clusters:
        dominant = find_dominant_failure(cluster)
        dominant_failures.append(dominant)
    
    # Шаг 3: Последовательная обработка доминирующих сбоев
    # с учетом их взаимного влияния
    current_schedule = get_current_schedule()
    
    for i, failure in enumerate(dominant_failures):
        # Учитываем изменения, внесенные обработкой предыдущих сбоев
        impact_forecast = forecast_cross_impact(
            failure=failure,
            already_handled=dominant_failures[:i],
            current_schedule=current_schedule
        )
        
        # Адаптивная стратегия с учетом прогноза
        strategy = adapt_strategy_based_on_forecast(
            base_strategy=get_base_strategy(failure),
            impact_forecast=impact_forecast,
            remaining_failures=dominant_failures[i+1:]
        )
        
        # Выполнение с компенсацией побочных эффектов
        result = execute_with_side_effect_compensation(
            strategy=strategy,
            schedule=current_schedule,
            compensation_buffer=TimeSpan.FromMinutes(15)
        )
        
        current_schedule = result['schedule']
        
        # Если достигнут предел устойчивости - остановка
        if result['system_stability'] < 0.6:  # Порог устойчивости
            emergency_stabilization(current_schedule)
            break
    
    # Шаг 4: Глобальная оптимизация после экстренных мер
    optimized_schedule = global_post_crisis_optimization(
        schedule=current_schedule,
        optimization_criteria=['STABILITY', 'FAIRNESS', 'EFFICIENCY']
    )
    
    return optimized_schedule

7. МЕХАНИЗМЫ КОМПЕНСАЦИИ И ВОССТАНОВЛЕНИЯ

7.1. Алгоритм распределения компенсационных буферов:

python
def redistribute_compensation_buffers(schedule, stress_points):
    """
    Перераспределение временных буферов для компенсации сбоев
    """
    # Шаг 1: Идентификация "доноров" буферов
    buffer_donors = find_buffer_donors(
        schedule=schedule,
        criteria=[
            'HAS_EXCESS_BUFFER',      # Имеет избыточный буфер
            'LOW_RISK_PROFILE',       # Низкий риск сбоев
            'FLEXIBLE_TIME_WINDOW',   # Гибкое временное окно
            'NON_CRITICAL_CLIENT'     # Не критичный клиент
        ]
    )
    
    # Шаг 2: Идентификация "реципиентов" буферов
    buffer_recipients = find_buffer_recipients(
        schedule=schedule,
        stress_points=stress_points,
        criteria=[
            'HIGH_RISK_PROFILE',      # Высокий риск
            'TIGHT_TIME_WINDOW',      # Жесткое окно
            'CRITICAL_CLIENT',        # Важный клиент
            'MINIMAL_BUFFER'          # Мало буфера
        ]
    )
    
    # Шаг 3: Оптимальное перераспределение
    redistribution_plan = optimize_buffer_redistribution(
        donors=buffer_donors,
        recipients=buffer_recipients,
        schedule=schedule,
        objective='MAXIMIZE_SYSTEM_STABILITY'
    )
    
    # Шаг 4: Поэтапное применение
    new_schedule = apply_buffer_redistribution(
        schedule=schedule,
        plan=redistribution_plan,
        phase_duration=TimeSpan.FromMinutes(5)  # Постепенно, по 5 минут
    )
    
    return new_schedule

7.2. Алгоритм восстановления после каскадного сбоя:

python
def post_cascade_recovery(schedule, cascade_event):
    """
    Восстановление системы после серьезного каскадного сбоя
    """
    recovery_phases = [
        {
            'name': 'СТАБИЛИЗАЦИЯ',
            'duration': TimeSpan.FromMinutes(30),
            'objectives': ['STOP_CASCADE', 'PROTECT_CRITICAL', 'ISOLATE_DAMAGE']
        },
        {
            'name': 'ВОССТАНОВЛЕНИЕ',
            'duration': TimeSpan.FromHours(2),
            'objectives': ['RESTORE_CAPACITY', 'REASSIGN_URGENT', 'OPTIMIZE_LOCALLY']
        },
        {
            'name': 'ОПТИМИЗАЦИЯ',
            'duration': TimeSpan.FromHours(4),
            'objectives': ['GLOBAL_OPTIMIZATION', 'LOAD_BALANCING', 'BUFFER_RESTORATION']
        }
    ]
    
    recovered_schedule = schedule
    
    for phase in recovery_phases:
        phase_strategy = create_recovery_strategy(
            phase=phase,
            current_state=recovered_schedule,
            cascade_history=cascade_event.history
        )
        
        phase_result = execute_recovery_phase(
            strategy=phase_strategy,
            schedule=recovered_schedule,
            time_limit=phase['duration']
        )
        
        recovered_schedule = phase_result['schedule']
        
        # Проверка готовности к следующей фазе
        if not phase_result['phase_successful']:
            # Расширяем текущую фазу
            phase['duration'] += TimeSpan.FromMinutes(15)
            continue
        
        # Мониторинг прогресса восстановления
        recovery_metrics = calculate_recovery_metrics(
            original=schedule,
            current=recovered_schedule,
            phase=phase['name']
        )
        
        if recovery_metrics['stability_index'] >= 0.8:
            # Достигнута достаточная стабильность - переход к следующей фазе
            continue
        else:
            # Требуется дополнительное время
            phase['duration'] += TimeSpan.FromMinutes(30)
    
    # Финальная проверка
    final_validation = validate_recovery_completion(
        original_schedule=schedule,
        recovered_schedule=recovered_schedule,
        cascade_event=cascade_event
    )
    
    if final_validation['recovery_successful']:
        return {
            'status': 'FULL_RECOVERY',
            'schedule': recovered_schedule,
            'recovery_time': final_validation['total_recovery_time'],
            'efficiency_loss': final_validation['efficiency_loss_percentage']
        }
    else:
        return {
            'status': 'PARTIAL_RECOVERY',
            'schedule': recovered_schedule,
            'unresolved_issues': final_validation['remaining_issues'],
            'human_intervention_required': True
        }

8. ИНТЕЛЛЕКТУАЛЬНАЯ СИСТЕМА ПРИНЯТИЯ РЕШЕНИЙ

8.1. Нейросетевая оценка вариантов перерасчета:

text
Архитектура нейросети для оценки вариантов:

Входной слой (12 параметров):
1. Количество затронутых поставок
2. Средний приоритет клиентов
3. Общий объем риска (м³×приоритет)
4. Временной горизонт воздействия
5. Количество доступных машин
6. Среднее расстояние до объектов
7. Коэффициент заполнения машин
8. Запас по времени жизни бетона
9. Сложность логистики (1-10)
10. Погодные условия (индекс)
11. Дорожная ситуация (индекс)
12. Историческая надежность варианта

Скрытые слои (3 слоя по 8 нейронов):
- Анализ взаимосвязей параметров
- Выявление неочевидных паттернов
- Оценка рисков и возможностей

Выходной слой (4 оценки):
1. Вероятность успеха (0-1)
2. Ожидаемое время восстановления (минуты)
3. Прогнозируемые потери (денежные)
4. Качество расписания после (0-100)

8.2. Алгоритм принятия решений на основе ML:

python
def ml_enhanced_decision_making(options, historical_data):
    """
    Принятие решений с использованием машинного обучения
    """
    # Шаг 1: Извлечение признаков для каждого варианта
    feature_vectors = []
    for option in options:
        features = extract_features(option)
        feature_vectors.append(features)
    
    # Шаг 2: Прогнозирование результатов с помощью обученной модели
    predictions = prediction_model.predict(feature_vectors)
    
    # Шаг 3: Многокритериальная оптимизация
    optimal_option = multi_criteria_optimization(
        options=options,
        predictions=predictions,
        criteria_weights={
            'success_probability': 0.35,
            'recovery_time': 0.25,
            'financial_impact': 0.20,
            'schedule_quality': 0.20
        }
    )
    
    # Шаг 4: Проверка на аномалии
    anomaly_check = detect_anomalies(
        selected_option=optimal_option,
        historical_patterns=historical_data
    )
    
    if anomaly_check['is_anomaly']:
        # Выбор второго лучшего варианта
        optimal_option = get_second_best(
            options=options,
            predictions=predictions
        )
    
    return optimal_option

9. СИСТЕМА МОНИТОРИНГА И ПРОГНОЗИРОВАНИЯ КАСКАДОВ

9.1. Алгоритм раннего предупреждения:

python
def early_cascade_warning_system(schedule):
    """
    Система раннего предупреждения о потенциальных каскадных сбоях
    """
    # Шаг 1: Поиск "точек напряжения" в расписании
    stress_points = find_schedule_stress_points(
        schedule=schedule,
        indicators=[
            'BACK_TO_BACK_SLOTS',      # Слоты без буфера
            'TIGHT_TIME_WINDOWS',      # Жесткие окна клиентов
            'HIGH_RISK_COMBINATIONS',  # Рискованные комбинации поставок
            'OVERLOADED_TRUCKS',       # Перегруженные машины
            'GEOGRAPHIC_CONFLICTS'     # Географические конфликты
        ]
    )
    
    # Шаг 2: Расчет "индекса каскадного риска" для каждой точки
    cascade_risk_index = {}
    for point in stress_points:
        risk_score = calculate_cascade_risk(
            stress_point=point,
            schedule=schedule,
            historical_failures=load_failure_history()
        )
        
        cascade_risk_index[point] = risk_score
    
    # Шаг 3: Прогнозирование потенциальных каскадов
    potential_cascades = forecast_potential_cascades(
        stress_points=stress_points,
        risk_index=cascade_risk_index,
        simulation_count=1000  # Монте-Карло симуляция
    )
    
    # Шаг 4: Генерация превентивных рекомендаций
    preventive_recommendations = generate_preventive_recommendations(
        potential_cascades=potential_cascades,
        schedule=schedule,
        intervention_cost_threshold=10000  # Максимальная стоимость вмешательства
    )
    
    return {
        'high_risk_points': cascade_risk_index,
        'potential_cascades': potential_cascades,
        'preventive_actions': preventive_recommendations,
        'overall_risk_level': calculate_overall_risk_level(cascade_risk_index)
    }

10. ПРАКТИЧЕСКАЯ РЕАЛИЗАЦИЯ: ОГРАНИЧЕНИЯ И ОПТИМИЗАЦИИ

10.1. Ограничения реального времени:

python
def real_time_constrained_rescheduling(event, time_budget):
    """
    Перерасчет с жестким ограничением по времени
    """
    # Шаг 1: Быстрая оценка сложности
    complexity = estimate_rescheduling_complexity(event)
    
    # Шаг 2: Выбор стратегии в зависимости от доступного времени
    if time_budget < TimeSpan.FromMinutes(2):
        strategy = 'ULTRA_FAST_HEURISTIC'
        max_iterations = 100
        search_depth = 1
    elif time_budget < TimeSpan.FromMinutes(5):
        strategy = 'FAST_LOCAL_SEARCH'
        max_iterations = 1000
        search_depth = 2
    elif time_budget < TimeSpan.FromMinutes(10):
        strategy = 'BALANCED_OPTIMIZATION'
        max_iterations = 5000
        search_depth = 3
    else:
        strategy = 'COMPREHENSIVE_SEARCH'
        max_iterations = 20000
        search_depth = 4
    
    # Шаг 3: Адаптивный алгоритм с контролем времени
    start_time = datetime.now()
    best_solution = None
    
    while (datetime.now() - start_time) < time_budget:
        candidate = generate_candidate_solution(
            event=event,
            strategy=strategy,
            current_best=best_solution
        )
        
        candidate_score = evaluate_solution(candidate)
        
        if best_solution is None or candidate_score > best_solution['score']:
            best_solution = {
                'schedule': candidate,
                'score': candidate_score,
                'time_spent': datetime.now() - start_time
            }
        
        # Проверка прогресса
        if should_terminate_early(
            current_best=best_solution,
            time_remaining=time_budget - (datetime.now() - start_time),
            progress_rate=calculate_progress_rate()
        ):
            break
    
    return best_solution['schedule']

10.2. Балансировка качества и скорости:

Режим работы Время на перерасчет Качество решения Используется когда
Экстренный 30-60 секунд 60-70% от оптимального Поломка в час пик, риск схватывания бетона
Оперативный 2-5 минут 75-85% от оптимального Стандартные сбои в рабочее время
Тщательный 5-10 минут 85-95% от оптимального Плановые изменения, оптимизация
Аналитический 10-20 минут 95-99% от оптимального Анализ после смены, обучение системы

ЗАКЛЮЧЕНИЕ: ФИЛОСОФИЯ УПРАВЛЕНИЯ ХАОСОМ

Алгоритм каскадного перерасчета — это живая, адаптивная система, которая эволюционирует с каждым обработанным сбоем. Её ключевые принципы:

  1. Принцип минимального вмешательства: Менять только то, что необходимо

  2. Принцип управляемого распространения: Контролировать границы воздействия

  3. Принцип приоритетного спасения: Сначала важное, потом остальное

  4. Принцип обучаемости: Каждый сбой делает систему умнее

  5. Принцип отказоустойчивости: Всегда иметь план Б, В и Г

Итоговая формула успеха:

text
Эффективность_перерасчета = 
  (Скорость_реакции × 0.3) + 
  (Качество_решения × 0.4) + 
  (Минимизация_изменений × 0.2) + 
  (Удовлетворенность_клиентов × 0.1)

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