Оптимизация логистики в 1С: используем алгоритм Флойда-Уоршелла для построения маршрутов

27.03.25

Разработка - Математика и алгоритмы

Оптимизация доставки в 1С: находим кратчайшие пути между всеми точками маршрута с помощью алгоритма Флойда-Уоршелла. Готовая реализация на 1С 8.3.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Оптимизация логистики в 1С: Используем алгоритм Флойда-Уоршелла для построения маршрутов:
.epf 10,71Kb
2
2 Скачать (1 SM) Купить за 1 850 руб.

В современном бизнесе оптимизация маршрутов и анализ связей между объектами играют ключевую роль в повышении эффективности и снижении затрат. Будь то логистика доставки товаров, планирование посещений филиалов или анализ цепочек поставок, знание кратчайших путей между различными точками позволяет принимать обоснованные решения и добиваться конкурентных преимуществ.

Для решения этих задач существует множество алгоритмов, одним из которых является алгоритм Флойда-Уоршелла. В этой статье мы рассмотрим реализацию этого мощного инструмента на платформе 1С 8.3, чтобы вы могли легко интегрировать его в свои бизнес-процессы.

Какие еще алгоритмы существуют?

Помимо алгоритма Флойда-Уоршелла, для поиска кратчайших путей часто используются алгоритм Дейкстры, алгоритм Беллмана-Форда и алгоритм A*. Каждый из них имеет свои особенности, преимущества и недостатки, определяющие область его применения.

Чем алгоритм Флойда-Уоршелла отличается от алгоритма Дейкстры?

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

Алгоритм Флойда-Уоршелла, в свою очередь, находит кратчайшие пути между всеми парами вершин в графе. Это значит, что после его выполнения вы будете знать кратчайшее расстояние и маршрут между любыми двумя точками в вашей сети.

Когда какой алгоритм выбирать?

  • Используйте алгоритм Дейкстры, если вам нужно найти кратчайшие пути от одной начальной точки до всех остальных. Это более эффективно, чем Флойда-Уоршелла, если вам не нужны расстояния между всеми парами вершин.
  • Используйте алгоритм Флойда-Уоршелла, если вам нужно знать кратчайшие расстояния между всеми парами вершин. Это необходимо, например, для анализа связности графа, поиска транзитивного замыкания или для решения задач, где требуется информация о кратчайших путях между любыми двумя точками.

В чем преимущества и недостатки алгоритма Флойда-Уоршелла?

  • Преимущества:
  1. Простота реализации.
  2. Возможность найти кратчайшие пути между всеми парами вершин.
  3. Возможность обнаружения циклов отрицательного веса.
  • Недостатки:
  1. Более высокая вычислительная сложность по сравнению с алгоритмом Дейкстры (O(n^3) против O(n^2) или O(n log n) с использованием приоритетной очереди). Это может быть критично для очень больших графов.
  2. Требует больше памяти для хранения матрицы смежности и матрицы расстояний.

Что вы узнаете из этой статьи?

В этой статье мы подробно рассмотрим реализацию алгоритма Флойда-Уоршелла на платформе 1С 8.3, научимся строить матрицу смежности, применять алгоритм и выводить результаты, включая найденные пути. Также мы рассмотрим обнаружение циклов отрицательного веса и примеры практического применения этого мощного инструмента в бизнес-задачах. 

Теория алгоритма Флойда-Уоршелла:

Представьте, что МатрицаРасстояний- это ваша личная карта дорог между офисами вашей компании. Вы хотите знать самый быстрый способ добраться из любого офиса в любой другой.

  • Что такое офисы? В нашем примере у нас 4 офиса (пронумерованы от 1 до 4). РазмерГрафа = 4; говорит об этом.
  • Что такое дороги? Дороги – это прямые маршруты между офисами. МатрицаРасстояний показывает длину каждой прямой дороги. Если прямой дороги нет, то пишем “Бесконечность” (Бесконечность = 1000000;).

Теперь разберем код, как эта карта создается:

МатрицаРасстояний = Новый Массив();
  • Это: Мы берем чистый лист бумаги, чтобы нарисовать нашу карту дорог (МатрицаРасстояний ).
    Строка1 = Новый Массив(РазмерГрафа);
    Строка1[0] = 0;
    Строка1[1] = 5;
    Строка1[2] = Бесконечность;
    Строка1[3] = 10;
    МатрицаРасстояний.Добавить(Строка1);

     

  • Это: Мы рисуем первую строку карты. Эта строка показывает, как добраться из ОФИСА №1 в другие офисы:
    • Строка1[0] = 0; : Из офиса №1 в офис №1 (в себя) – расстояние 0 (никуда ехать не надо).
    • Строка1[1] = 5; : Из офиса №1 в офис №2 – расстояние 5 км (например).
    • Строка1[2] = Бесконечность; : Из офиса №1 в офис №3 – прямой дороги НЕТ (очень далеко, "Бесконечность").
    • Строка1[3] = 10; : Из офиса №1 в офис №4 – расстояние 10 км.
  • МатрицаРасстояний.Добавить(Строка1); : Мы добавляем эту информацию на наш “лист карты”.
    Строка2 = Новый Массив(РазмерГрафа);
    Строка2[0] = Бесконечность;
    Строка2[1] = 0;
    Строка2[2] = 3;
    Строка2[3] = Бесконечность;
    МатрицаРасстояний.Добавить(Строка2);

     

  • Это: Мы рисуем вторую строку карты. Эта строка показывает, как добраться из ОФИСА №2 в другие офисы:
    • Строка2[0] = Бесконечность; : Из офиса №2 в офис №1 – прямой дороги НЕТ.
    • Строка2[1] = 0; : Из офиса №2 в офис №2 (в себя) – расстояние 0.
    • Строка2[2] = 3; : Из офиса №2 в офис №3 – расстояние 3 км.
    • Строка2[3] = Бесконечность; : Из офиса №2 в офис №4 – прямой дороги НЕТ.
  • МатрицаРасстояний.Добавить(Строка2); : Мы добавляем эту информацию на наш “лист карты”.
  • и т.д.

    Алгоритм берет эту "карту прямых дорог" и начинает искать пути подлиннее, через другие офисы. Например, может оказаться, что из офиса №1 в офис №3 нет прямой дороги, но можно доехать до офиса №2 (5 км), а потом из офиса №2 в офис №3 (3 км). Тогда общий путь будет 5 + 3 = 8 км. Это лучше, чем “Бесконечность”!

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

 

Реализация алгоритма Флойда-Уоршелла в 1С 8.3:

&НаСервере
Процедура ФлойдаУоршелла(МатрицаРасстояний, РазмерГрафа, Бесконечность, МатрицаПредков)

    Для k = 0 По РазмерГрафа - 1 Цикл  // "Промежуточный офис"
        Для i = 0 По РазмерГрафа - 1 Цикл  // Откуда едем (начальный офис)
            Для j = 0 По РазмерГрафа - 1 Цикл  // Куда едем (конечный офис)
                Если (МатрицаРасстояний[i][k] <> Бесконечность И МатрицаРасстояний[k][j] <> Бесконечность) Тогда
                    // Если из i в k и из k в j можно доехать
                    Если МатрицаРасстояний[i][j] > МатрицаРасстояний[i][k] + МатрицаРасстояний[k][j] Тогда
                        // И если путь через k короче, чем прямой путь из i в j
                        МатрицаРасстояний[i][j] = МатрицаРасстояний[i][k] + МатрицаРасстояний[k][j];
                        МатрицаПредков[i][j] = k;  // Запоминаем, что лучший путь через k
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
	
    // Проверка на циклы отрицательного веса
    Для i = 0 По РазмерГрафа - 1 Цикл
        Если МатрицаРасстояний[i][i] < 0 Тогда
            Сообщить("Обнаружен цикл отрицательного веса!");
            Возврат; // Прерываем выполнение, если цикл обнаружен
        КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Код ФлойдаУоршелла:

  • Для k = 0 По РазмерГрафа - 1 Цикл : Этот цикл перебирает все возможные "промежуточные офисы" (офис k).
  • Для i = 0 По РазмерГрафа - 1 Цикл : Этот цикл перебирает все возможные "начальные офисы" (офис i).
  • Для j = 0 По РазмерГрафа - 1 Цикл : Этот цикл перебирает все возможные "конечные офисы" (офис j).
  • Если (МатрицаРасстояний[i][k] <> Бесконечность И МатрицаРасстояний[k][j] <> Бесконечность) Тогда : Проверяем, можно ли вообще доехать из офиса i в офис k, и из офиса k в офис j. Если хотя бы один из этих путей равен "Бесконечности", то ехать через офис k нет смысла.
  • Если МатрицаРасстояний[i][j] > МатрицаРасстояний[i][k] + МатрицаРасстояний[k][j] Тогда : Проверяем, короче ли путь из офиса i в офис j через офис k, чем прямой путь из офиса i в офис j.
  • МатрицаРасстояний[i][j] = МатрицаРасстояний[i][k] + МатрицаРасстояний[k][j]; : Если путь через офис k короче, то мы обновляем расстояние в МатрицеРасстояний.
  • МатрицаПредков[i][j] = k; : Запоминаем в МатрицеПредков, что лучший путь из офиса i в офис j проходит через офис k. Это поможет нам потом восстановить маршрут.

Этот код берет вашу "карту дорог" и улучшает ее, находя самые короткие пути между всеми офисами, даже если нет прямых дорог!

Мы уже определили карту дорог (МатрицаРасстояний) в примере выше (4 офиса, расстояния между ними). Нажимаем кнопку "Запустить алгоритм" в нашей обработке.

В текстовом поле "РезультатАлгоритма" мы должны увидеть следующую информацию (это пример, значения могут отличаться в зависимости от реализации функции ВосстановитьПуть):

Расстояние от 1 до 1: 0
Путь: 1

Расстояние от 1 до 2: 5
Путь: 1 -> 2

Расстояние от 1 до 3: 8
Путь: 1 -> 2 -> 3

Расстояние от 1 до 4: 9
Путь: 1 -> 2 -> 3 -> 4

Расстояние от 2 до 1: Бесконечность

Расстояние от 2 до 2: 0
Путь: 2

Расстояние от 2 до 3: 3
Путь: 2 -> 3

Расстояние от 2 до 4: 4
Путь: 2 -> 3 -> 4

Расстояние от 3 до 1: Бесконечность

Расстояние от 3 до 2: Бесконечность

Расстояние от 3 до 3: 0
Путь: 3

Расстояние от 3 до 4: 1
Путь: 3 -> 4

Расстояние от 4 до 1: Бесконечность

Расстояние от 4 до 2: Бесконечность

Расстояние от 4 до 3: Бесконечность

Расстояние от 4 до 4: 0
Путь: 4

Анализ результатов (построчно):

  • Расстояние от 1 до 1: 0, Путь: 1: Всё верно, расстояние от вершины 1 до самой себя равно 0.
  • Расстояние от 1 до 2: 5, Путь: 1 -> 2: В МатрицеРасстояний[0][1] (от 1 до 2) изначально было 5. Алгоритм не нашел более короткого пути. Всё правильно.
  • Расстояние от 1 до 3: 8, Путь: 1 -> 2 -> 3: В МатрицеРасстояний[0][2] (от 1 до 3) изначально было Бесконечность. Алгоритм нашел путь через вершину 2: 1 -> 2 (5) + 2 -> 3 (3) = 8. Это и есть кратчайший путь.
  • Расстояние от 1 до 4: 9, Путь: 1 -> 2 -> 3 -> 4: В МатрицеРасстояний[0][3] (от 1 до 4) изначально было 10. Алгоритм нашел путь через вершины 2 и 3: 1 -> 2 (5) + 2 -> 3 (3) + 3 -> 4 (1) = 9. Это и есть кратчайший путь.
  • Расстояние от 2 до 1: Бесконечность: В МатрицеРасстояний[1][0] (от 2 до 1) изначально было Бесконечность. Значит, из вершины 2 в вершину 1 нет пути (или он очень длинный). Алгоритм не смог найти путь короче.
  • Расстояние от 2 до 2: 0, Путь: 2: Всё верно, расстояние от вершины 2 до самой себя равно 0.
  • Расстояние от 2 до 3: 3, Путь: 2 -> 3: В МатрицеРасстояний[1][2] (от 2 до 3) изначально было 3. Алгоритм не нашел более короткого пути. Всё правильно.
  • Расстояние от 2 до 4: 4, Путь: 2 -> 3 -> 4: В МатрицеРасстояний[1][3] (от 2 до 4) изначально было Бесконечность. Алгоритм нашел путь через вершину 3: 2 -> 3 (3) + 3 -> 4 (1) = 4. Это и есть кратчайший путь.
  • Расстояние от 3 до 1: Бесконечность: В МатрицеРасстояний[2][0]  (от 3 до 1) изначально было Бесконечность. Алгоритм не смог найти путь короче.
  • Расстояние от 3 до 2: Бесконечность: В МатрицеРасстояний[2][1] (от 3 до 2) изначально было Бесконечность Алгоритм не смог найти путь короче.
  • Расстояние от 3 до 3: 0, Путь: 3: Всё верно, расстояние от вершины 3 до самой себя равно 0.
  • Расстояние от 3 до 4: 1, Путь: 3 -> 4: В МатрицеРасстояний[2][3] (от 3 до 4) изначально было 1. Алгоритм не нашел более короткого пути. Всё правильно.
  • Расстояние от 4 до 1: Бесконечность: В МатрицеРасстояний[3][0] (от 4 до 1) изначально было Бесконечность Алгоритм не смог найти путь короче.
  • Расстояние от 4 до 2: Бесконечность: В МатрицеРасстояний[3][1] (от 4 до 2) изначально было Бесконечность. Алгоритм не смог найти путь короче.
  • Расстояние от 4 до 3: Бесконечность: В МатрицеРасстояний[3][2] (от 4 до 3) изначально было Бесконечность. Алгоритм не смог найти путь короче.
  • Расстояние от 4 до 4: 0, Путь: 4: Всё верно, расстояние от вершины 4 до самой себя равно 0.

 

Что произойдет при изменении МатрицаРасстояний[2][3] = -1; и наличии проверки на цикл отрицательного веса:

  1. Изменение матрицы смежности: Значение МатрицаРасстояний[2][3] меняется на -1.

  2. Выполнение алгоритма Флойда-Уоршелла: Алгоритм начинает свою работу, перебирая все возможные пути между вершинами.

  3. Обнаружение цикла отрицательного веса:

    • В какой-то момент алгоритм обнаружит, что расстояние от вершины 3 до самой себя можно уменьшить, пройдя через вершину 4:
      • Путь от 3 до 3 через 4: 3 -> 4 (-1) + 4 -> 3 (Бесконечность). Изначально Бесконечность не даст обнаружить, но при этом 4 -> 4 = 0. Надо проверить.
    • Т.е. нужно сделать проверку 4 -> 3 и 3 -> 4.
  4. Сработает проверка на цикл отрицательного веса:

    • Когда алгоритм дойдет до этапа, когда k = 3 и i = 3 (то есть, рассматривает вершину 3 как промежуточную для пути из 3 в 3), условие МатрицаРасстояний[i][i] < 0 станет истинным.
    • Потому что он найдет, что путь из вершины 3 в вершину 3 (через вершину 4) стал отрицательным.
  5. Вывод сообщения и прерывание выполнения:

    • Будет выведено сообщение: "Обнаружен цикл отрицательного веса!"
    • Функция ЗапуститьАлгоритмНаСервере прервет свое выполнение (Возврат;).

Результат:

  • Алгоритм Флойда-Уоршелла не завершится. Он прервет свое выполнение, как только обнаружит цикл отрицательного веса.
  • В текстовых полях НачальныеДанные и РезультатАлгоритма вы увидите только исходную матрицу смежности (в НачальныеДанные) и сообщение об обнаруженном цикле отрицательного веса (в сообщении). Значения в текстовом поле РезультатАлгоритма  либо не изменятся, либо будут частично изменены (в зависимости от того, как быстро сработает проверка).

Важно:

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

 

P.S упоминался в статье Алгоритм A*.  Алгоритм A* (А звезда) – это алгоритм поиска пути, который эффективно находит оптимальный маршрут от начальной до конечной точки. Он комбинирует в себе преимущества алгоритма Дейкстры (гарантия нахождения кратчайшего пути) и эвристического поиска (скорость). A* использует эвристическую функцию, оценивающую "стоимость" достижения цели из текущей точки. Алгоритм выбирает для расширения вершину с наименьшим значением функции f(n) = g(n) + h(n), где g(n) – стоимость пути от начальной точки до текущей, а h(n) – эвристическая оценка стоимости пути от текущей до конечной точки. A* гарантирует нахождение оптимального пути, если эвристика допустима (не переоценивает расстояние до цели).

Статья была протестирована на платформе 1С:Предприятие 8.3, в среде разработки и на реальных примерах, демонстрирующих применение алгоритма Флойда-Уоршелла в типовых конфигурациях.

Статья ориентирована на:

  • Разработчиков 1С: которые хотят углубить свои знания в области алгоритмов и научиться применять их в своих проектах.
  • Внедренцев 1С: стремящихся оптимизировать бизнес-процессы клиентов с помощью эффективных решений.
  • Пользователей 1С: интересующихся возможностями платформы для решения сложных задач, таких как логистика, анализ данных и оптимизация.

Проверено на следующих конфигурациях и релизах:

  • 1С:ERP Управление предприятием 2, релизы 2.5.15.111

Алгоритм Флойда-Уоршелла 1С 8.3 кратчайшие пути матрица смежности граф вершины ребра маршруты оптимизация реализация код логистика сети анализ динамическое программирование взаиморасчеты производство циклы алгоритм Дейкстры пути.

См. также

Математика и алгоритмы Программист Платформа 1C v8.2 1C:Бухгалтерия Россия Абонемент ($m)

На написание данной работы меня вдохновила работа @glassman «Переход на ClickHouse для анализа метрик». Автор анализирует большой объем данных, много миллионов строк, и убедительно доказывает, что ClickHouse справляется лучше PostgreSQL. Я же покажу как можно сократить объем данных в 49.9 раз при этом: 1. Сохранить значения локальных экстремумов 2. Отклонения от реальных значений имеют наперед заданную допустимую погрешность.

1 стартмани

30.01.2024    6356    stopa85    12    

39

Математика и алгоритмы Бесплатно (free)

Разработка алгоритма, построенного на модели симплекс-метода, для нахождения оптимального раскроя.

19.10.2023    11918    user1959478    56    

37

Математика и алгоритмы Разное Платформа 1С v8.3 1C:Бухгалтерия Россия Абонемент ($m)

Расширение (+ обработка) представляют собою математический тренажер. Ваш ребенок сможет проверить свои знание на математические вычисление до 100.

2 стартмани

29.09.2023    6145    maksa2005    8    

26

Математика и алгоритмы Инструментарий разработчика Программист Платформа 1С v8.3 Мобильная платформа Россия Абонемент ($m)

Что ж... лучше поздно, чем никогда. Подсистема 1С для работы с регулярными выражениями: разбор выражения, проверка на соответствие шаблону, поиск вхождений в тексте.

1 стартмани

09.06.2023    14324    8    SpaceOfMyHead    20    

63

Математика и алгоритмы Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Три задачи - три идеи - три решения. Мало кода, много смысла. Мини-статья.

03.04.2023    7399    RustIG    9    

28

Механизмы платформы 1С Математика и алгоритмы Программист Платформа 1С v8.3 Россия Бесплатно (free)

В статье анализируются средства платформы для решения системы линейных уравнений в 1С. Приводятся доводы в пользу некорректной работы встроенных алгоритмов, а значит потенциально некорректного расчета себестоимости в типовых конфигурациях.

23.11.2022    6553    gzharkoj    14    

25

Математика и алгоритмы Программист Платформа 1С v8.3 Россия Абонемент ($m)

Обычно под распределением понимают определение сумм пропорционально коэффициентам. Предлагаю включить сюда также распределение по порядку (FIFO, LIFO) и повысить уровень размерности до 2-х. 1-ое означает, что распределение может быть не только пропорциональным, но и по порядку, а 2-ое - это вариант реализации матричного распределения: по строкам и столбцам. Возможно вас заинтересует также необычное решение этой задачи через создание DSL на базе реализации текучего интерфейса

1 стартмани

21.03.2022    9751    7    kalyaka    11    

45
Оставьте свое сообщение