Подтвердить что ты не робот

Какова самая быстрая реализация Dijkstra, которую вы знаете (на С++)?

Недавно я приложил к моему проекту 3-ю версию алгоритма Дейкстры для кратчайшего пути одного источника.

Я понимаю, что существует множество различных реализаций, которые сильно различаются по производительности, а также отличаются качеством результата на больших графиках. С моим набором данных ( > 100.000 вершин) время выполнения варьируется от 20 минут до нескольких секунд. Самые короткие пути также изменяются на 1-2%.

Какая наилучшая реализация вы знаете?

EDIT: Мои данные - это гидравлическая сеть с 1 - 5 вершинами на node. Это сопоставимо с уличной картой. Я внесла некоторые изменения в уже ускоренный алгоритм (используя отсортированный список для всех остальных узлов) и теперь обнаружил те же результаты за долю времени. Некоторое время я искал такое. Интересно, существует ли такая реализация.

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

ИЗМЕНИТЬ 2: Я узнал, что различия в найденном пути действительно являются моей ошибкой. Я вставил специальную обработку для некоторых вершин (только в одном направлении) и забыл об этом в другой реализации.

НО im все же более чем удивлен тем, что Dijkstra можно резко ускорить следующим изменением: В общем случае алгоритм Дейкстры содержит петлю типа:

MyListType toDoList; // List sorted by smallest distance 
InsertAllNodes(toDoList);
while(! toDoList.empty())
{
    MyNodeType *node = *toDoList.first();
    toDoList.erase(toDoList.first());
    ...
}

Если вы немного измените это, он будет работать одинаково, но будет лучше:

MyListType toDoList; // List sorted by smallest distance 
toDoList.insert(startNode);
while(! toDoList.empty())
{
    MyNodeType *node = *toDoList.first();
    toDoList.erase(toDoList.first());
    for(MyNeigborType *x = node.Neigbors; x != NULL; x++)
    {
        ...
        toDoList.insert(x->Node);
    }
}

Кажется, что эта модификация уменьшает время выполнения по порядку не по величине, а по порядку экспоненты. Это уменьшило мою форму выполнения 30 секунд до менее чем 2. Я не могу найти эту модификацию в любой литературе. Также очень ясно, что причина кроется в сортированном списке. вставка/стирание выполняется намного хуже с 100 000 элементами, которые с полной рукой.

ОТВЕТ:

После многих поисковых запросов я нашел это сам. Ответ явно: увеличить график lib. Удивительно - я не нашел это довольно долгое время. Если вы считаете, что между реализациями Dijkstra нет изменений производительности, см. wikipedia.

4b9b3361

Ответ 1

Наилучшие реализации, известные для дорожных сетей ( > 1 миллион узлов), имеют время запроса, выраженное в микро секундах. См. Более подробную информацию о 9-й проблеме внедрения DIMACS (2006). Обратите внимание, что это не просто Dijkstra, конечно, поскольку все дело в том, чтобы быстрее получать результаты.

Ответ 2

Может быть, я не отвечаю на ваш вопрос. Моя точка зрения заключается в том, почему использовать Dijkstra, когда есть намного более эффективные алгоритмы для вашей проблемы. Если ваш граф заполняет треугольное свойство (это графа евклидова)

| аЬ | + | Ьс | > | ac |

(расстояние от node a до node b плюс расстояние от node b до node c больше, чем расстояние от node a до node c), тогда вы можете применить A * алгоритм. Этот алгоритм довольно эффективен. В противном случае используйте эвристику. Реализация не является основной проблемой. Используемый алгоритм имеет значение.

Ответ 3

Два момента, которые я хотел бы сделать: 1) Dijkstra vs A * Алгоритм Дейкстры - это алгоритм динамического программирования, а не эвристический. A * является эвристическим, поскольку он также использует эвристическую функцию (пусть h (x)) "оценивает", как близок точка x до конечной точки. Эта информация используется в последующих решениях о том, какие узлы следует исследовать далее.

В таких случаях, как евклидово граф, A * хорошо работает, потому что эвристическая функция легко определить (например, можно просто использовать евклидово расстояние). Однако для неевклидовых графов может быть сложнее определить эвристическую функцию, а неправильное определение может привести к неоптимальному пути.

Следовательно, dijkstra имеет преимущество перед A *, которое заключается в том, что оно работает для любого общего графика (за исключением того, что в некоторых случаях A * быстрее). Вполне возможно, что некоторые реализации используют эти алгоритмы взаимозаменяемо, что приводит к различным результатам.

2) Алгоритм dijkstra (и другие, такие как A *) используют очередь приоритетов, чтобы получить следующий node для изучения. Хорошая реализация может использовать кучу вместо очереди, а еще лучше - использовать купон фибоначчи. Это может объяснить разные времена выполнения.

Ответ 4

В последний раз, когда я проверил, Dijkstra Algorithm возвращает оптимальное решение. Все "истинные" реализации Dijkstra должны возвращать одинаковый результат каждый раз.

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

Ответ 5

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

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

Проблема в том, что не существует "одной самой быстрой" версии алгоритма.