Алгоритм Дейкстры, чтобы найти все возможные кратчайшие пути

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

Так работает мой алгоритм для одного решения:

public void dijkstra( int graph[][] )
{
    int d[] = new int[ graph.length ];
    int dC[] = new int[ graph.length ];
    int p[] = new int[ graph.length ];

    for( int i = 0; i < graph.length; i++ ){
        d[ i ] = 100; dC[ i ] = 100; p[ i ] = -1;
    }
    d[ 0 ] = 0; dC[ 0 ] = 0;

    int i = 0, min = 200, pos = 0; //You can change the min to 1000 to make it the largest number
    while( i < graph.length ){
        //extract minimum
        for( int j = 0; j < dC.length; j++ ){
            if( min > d[ j ] && dC[ j ] != -1 ){
                min = d[ j ]; pos = j;
            }
        }
        dC[ pos ] = -1;

        //relax
        for( int j = 0; j < graph.length; j++ ){
            if( d[ j ] > graph[ pos ][ j ] + d[ pos ] ){
                d[ j ] = graph[ pos ][ j ] + d[ pos ];
                p[ j ] = pos;
            }
        }
        i++; min = 200;
    }

    for( int j = 0; j < p.length; j++ ){
        System.out.print( p[ j ] + " " );
    }
    System.out.print( "\n" );
    for( int j = 0; j < d.length; j++ ){
        System.out.print( d[ j ] + " " );
    }
    System.out.print( "\n" );
}

Ответ 1

Если вы посмотрите на алгоритм Дейкстры в псевдокодной форме здесь: Википедия Dijkstra Algorithm Pseudocode

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

Ответ 2

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

Ответ 3

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

Если нет или нет нулевого веса, или ваш график является DAG, то ваше решение по-прежнему проблематично: оно либо не создает все кратчайшие пути по мере необходимости, либо делает это с O(2^N) пространственной и временной сложностью. Но тогда, возможно, может быть столько кратчайших путей, поэтому вы не можете надеяться на лучшее в общем случае.

Это лучший источник для немного более общей проблемы: Поиск k самых коротких путей (Eppstein). Вы можете применить это, итерируя кратчайшие пути, останавливаясь на первом пути, который больше, чем предыдущий.

Для ограниченной проблемы нахождения только (эквивалентных) кратчайших путей, намек Андерсона Имеса выше (это домашнее задание? В противном случае кто-то должен это описать) хорошо и намного проще, чем выше.

Ответ 4

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

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

  • для каждого ребра E в кратчайшем пути:
    • удалите E и снова запустите модифицированный Dijkstra над новым графиком
    • если кратчайший путь длиннее первого, остановите
    • else, повторите рекурсивное удаление одного ребра за раз из нового подграфа

Моя интуиция подсказывает мне, что она должна работать с увеличением сложности, пропорциональной длине (n по количеству ребер) первого решения... Если нет более короткого пути, он должен заканчиваться на первый раунд, если он найдет другой, он продолжит попытки n-1. Оценка худшего значения сложности по сравнению с исходным алгоритмом очень плохая (n! Я думаю?), Но это также означает, что существует множество путей, поэтому это работа, которая должна выполняться с помощью любого алгоритма...

edit: Думая немного больше, увеличение сложности может быть даже больше, чем факториал числа узлов первого найденного пути, так как второй может иметь еще больше узлов! Поэтому мне сложно оценить сложность этого метода, но он должен быть чем-то вроде числа допустимых решений, умноженное на среднее число узлов в путях, умноженное на число узлов в квадрате (этот последний термин является исходной сложностью немодифицированный алгоритм).

изменить 2: Я нашел исследовательский документ по этому вопросу, он требует подписки, чтобы получить полный текст, но, возможно, вы можете найти его где-то еще: http://ieeexplore.ieee.org/Xplore/login.jsp?reload=true&url=http%3A%2F%2Fieeexplore.ieee.org%2Fiel5%2F7719%2F21161%2F00982778.pdf%3Farnumber%3D982778&authDecision=-201

Ответ 5

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

Алгоритм отлично работает с простыми взвешенными графами, поэтому должен работать на ваш случай.

Автор сравнивает его с Dijkstra, как в том, как он работает, так и в сравнении сложности во время выполнения.

 В псевдокоде, перефразируя бумагу:

1. H is a heap of paths sorted on the weights of these paths, either
     a. lexicographically and decreasing in each element of the weight vector
     b. on the negative sum of all the elements in the weight vector
   Initially, H contains only path p0 (the starting point) the weight of which is O.
2. S1 through Sv are sets associated with vertices v1 through vv respectively.
   These sets contain the maximal paths to each vertex, as they are discovered.
   Initially, all sets are empty.
3. a. While (H is not empty) do begin
   b.   remove the root of H, p;
   c.   if p is not dominated by any of the paths in Sn where vn is last vertex of p
   d.     add it to Sn (the set of maxima for vertex vn)
   e.     for each possible extensions q of path p
   g.       if path q to node vm is not yet dominated by the maxima in Sm
   h.         insert q into H

Ответ 6

FloydWarshallShortestPaths класс JgraphT находит все кратчайшие пути. На основании вышеприведенных комментариев вы ищете кратчайшие пути между двумя вершинами. Вы можете использовать метод getShortestPaths, который вернет все кратчайшие пути из вершины ко всем другим вершинам. Затем вы можете фильтровать результат, который вас интересует.

Ответ 7

Я просто решил задачу найти все возможные кратчайшие пути на leetcode.com, используя алгоритм Дейкстра.

Единственное различие заключается в том, как вы извлекаете информацию из массивов "родители" и "расстояния".

Основная идея

  • вы переходите от цели к источнику и от каждого node в своем оптимальном пути (массив "родители" ),
  • вы ищете соседей, у которых были одинаковые минимальные расстояния до источника, такого как записанный родительский элемент, и
  • затем рекурсивно перемещаясь по всем возможным родителям, пока не дойдете до источника.

Ниже приведен код в Python.

if parent[endNode] > -1: # -1 means no path at all
            self.traversingAllNodes(parents, shortestDistances, endNode, [endNode])
    return self.finalList

def traversingAllNodes(self, parents, distances, startNode, path):
    if parents[startNode] == -1:
        self.saveFound(path) # saving one path
        return
    currentNode = startNode
    parent = parents[currentNode] # recorded parent
    optimalDistance = distances[parent] # distance from parent to source
    for node in self.graph[currentNode]: # moving via neighbords
        if distances[node] == optimalDistance: 
            path.append(node)
            self.traversingAllNodes(parents, distances, node, path)
            path.remove(node)