создание функции стоимости в jgrapht

jgrapht поддерживает идею размещения веса (стоимости) на ребре/вершине между двумя узлами. Этого можно добиться с помощью класса DefaultWeightedEdge.

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

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

Допустим, у вас есть граф, похожий на шахматную доску (8x8 полей, каждое поле является узлом). Все ребра имеют вес 1. Чтобы двигаться в машине из левого нижнего угла в диагональный угол (правый верхний), есть много путей стоимостью 16. Вы можете выбрать диагональный путь в стиле зик-зак, или вы может сначала пройти все узлы вправо, а затем все узлы вверх. Разница в том, что при выполнении зикзака вам нужно вращаться в направлении движения. Вы вращаетесь 16 раз. При перемещении сначала вправо, а затем вверх вам нужно повернуться только один раз (может быть, два раза, в зависимости от вашей начальной ориентации). Таким образом, путь зик-зак, с точки зрения джикстры, идеален. С логической точки зрения это худшее.

Короче говоря: как я могу установить некоторые затраты на узел или ребро в зависимости от предыдущего ребра/узла на этом пути? Я не нашел ничего похожего в исходном коде jgrapht. Или есть лучший алгоритм для использования?


person Remo Liechti    schedule 24.11.2016    source источник


Ответы (1)


Это не проблема JGraphT, а проблема алгоритма графа. Вам нужно подумать о том, как закодировать эту проблему и формализовать это более подробно.

  1. Включение весов в вершины, как правило, несложно. Скажем, что каждая вершина представляет посещение клиента, которое занимает a_i времени. Это можно закодировать в графе, добавив a_i/2 к стоимости каждой входящей дуги в узле i, а также a_i/2 к стоимости каждой исходящей дуги.

  2. Функция стоимости, в которой стоимость путешествия из j в k зависит от дуги (i,j), которую вы использовали для перехода в j, более сложна.

Подход а.: Используйте алгоритм динамического программирования (маркировки). Это, пожалуй, самое простое. Вы можете определить свою функцию стоимости как рекурсивную функцию, где стоимость прохождения дуги зависит от стоимости предыдущей дуги.

Подход б.: С помощью некоторых трюков вы сможете закодировать затраты в графе, добавив к нему дополнительные узлы. Вот пример:

Дан граф с вершинами {a,b,c,d,e}, с дугами: (a,e), (e,b), (c,e), (e,d). Этот граф представляет собой перекресток с вершиной e, находящейся посередине. Переход из a->e->b (прямо) бесплатный, однако поворот из a->e->d требует дополнительного времени. Аналогично для c->e->d (прямой) свободный и c->e->b (поворот) должен быть оштрафован. Разделить вершину e на 4 новые вершины: e1,e2,e3,e4. Добавьте следующие дуги: (a,e1), (e3,b), (c,e2), (e4,d), (e2, e3), (e1, e3), (e1, e4), (e2, д4). (e1,e4) и (e2,e3) могут иметь положительный вес, чтобы оштрафовать поворот.

person Joris Kinable    schedule 24.11.2016
comment
Мой комментарий относительно JGraphT был больше в том направлении, если он поддерживает это без явного взрыва графа. Я придумал ту же идею, что и ваш подход b. Однако я не уверен, насколько плохо это влияет на работу джикстры. У нас уже есть 11 000 дуг на этом графике. График представляет собой несколько статическую сетку. Таким образом, в худшем случае мы генерируем из 4 дуг до 30 новых дуг. Таким образом, мы получаем примерно 80 000 дуг. Подход а: поставляет ли jgrapht некоторые алгоритмы маркировки? Я не нашел обзора поддерживаемых алгоритмов, кроме того, что есть в javadoc - person Remo Liechti; 24.11.2016
comment
Мой совет будет просто попробовать. Не оптимизируйте то, что «достаточно быстро» для вашего приложения. Если вам нужно выполнить несколько вычислений кратчайшего пути, то Дейкстры может быть достаточно. В качестве альтернативы вы можете попробовать использовать поиск A*, который использует допустимую эвристику. Это может быть быстрее, если ваши данные имеют определенную структуру. Ваш пример с шахматной доской будет тривиально решен A*. Если вам нужно много вычислять кратчайшие пути, а ваш график не меняется, рассмотрите возможность использования FloydWarshallShortestPaths для массового расчета всех кратчайших путей. - person Joris Kinable; 28.11.2016
comment
JGraphT в настоящее время не имеет алгоритма маркировки, поскольку такая реализация обычно довольно специфична для приложения. Однако реализовать алгоритм маркировки несложно. Взгляните на книгу Network Flows: Theory, Algorithms, and Applications, авторы Ahuja, Magnanti, Orlin, где содержится высокоуровневое описание алгоритма установки меток. . - person Joris Kinable; 28.11.2016
comment
Я уже начал работать над пробной версией подхода, похожего на ваш подход b. A* действительно может работать, поскольку у нас есть сетка, поэтому эвристика должна работать. Спасибо за упоминание FloydWarshall, я проверю этот. К сожалению, граф много раз манипулируется для отслеживания заблокированных узлов. Но, может быть, я все же смогу использовать некоторые из них повторно. Книга звучит интересно. Спасибо. - person Remo Liechti; 28.11.2016