Все возможные пути в циклическом неориентированном графе - PullRequest
6 голосов
/ 17 июня 2010

Я пытаюсь разработать алгоритм, который идентифицирует все возможные пути между двумя узлами на графике, как в этом примере:

image.

На самом деле, мне просто нужно знать, какие узлы появляются во всех существующих путях.

в Интернете есть только ссылки о DFS, A * или dijkstra, но я думаю, что в этом случае они не работают.

Кто-нибудь знает, как это решить?

Ответы [ 5 ]

4 голосов
/ 17 июня 2010

Вы можете найти все пути, используя DFS, как | Влад описал. Чтобы найти, какие узлы появляются в каждом пути, вы можете просто сохранить массив логических значений, который сообщает, появился ли каждый узел в каждом пути до сих пор. Когда ваша DFS найдет путь, просмотрите каждую вершину , а не в пути и установите для соответствующего значения массива значение false. Когда вы закончите, только вершины со значениями true будут теми, которые появляются на каждом пути.

псевдокод:

int source;
int sink;
int nVerts;
bool inAllPaths[nVerts]; // init to all true
bool visited[nVerts]; // init to all false
stack<int> path; // init empty

bool dfs(int u)
  if (visited[u])
    return;
  if (u == sink)
    for i = 0 to nVerts-1
      if !stack.contains(i)
        inAllPaths[i] = false;
    return true;
  else
    visited[u] = true;
    stack.push(u);
    foreach edge (u, v)
      dfs(v);
    stack.pop();
    visited[u] = false;
    return false;


main()
  dfs(source);
  // inAllPaths contains true at vertices that exist in all paths
  // from source to sink.

Однако этот алгоритм не очень эффективен. Например, в полном графе из n вершин (все вершины имеют ребра для всех остальных), число путей будет n! (n факториал).

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

псевдокод:

// Using the same initialisation as above, but with a slight modification
// to dfs: change the foreach loop to
foreach edge (u, v)
  if (dfs(v))
    return true; // exit as soon as we find a path

main()
  for i = 0 to nVerts-1
    set all visited to false;
    if (inAllPaths[i])
      visited[i] = true;
      if (dfs(source))
        inAllPaths[i] = false;
      visited[i] = false;

К сожалению, это все еще имеет экспоненциальный худший случай при поиске пути. Вы можете исправить это, изменив поиск на поиск в ширину. Если я не ошибаюсь, это должно дать вам производительность O (VE).

1 голос
/ 07 декабря 2012

Я знаю, что это было какое-то время, но я пришел сюда в поисках некоторого алгоритма, чтобы найти все пути (не только кратчайший путь) в SQL или Java, и я нашел эти три (я просто публикую их, чтобы сохранить концепции организованными):

Если вы добавите в комментарии строки start with n1... и where n2..., запрос вернет все пути на всем графике.

1 голос
/ 17 июня 2010

Для этой проблемы я сначала получил бы дерево t, сформированное из DFS на одном из ваших целевых узлов u. Затем закрасьте все узлы, скажем, синим, которые находятся в поддереве s с корнем в вашем втором целевом узле v.

For each node k in subtree s, 
    if k has an edge to a non-blue node x 
    then k is true and x is true.

Также отметьте v как true. Наконец, я бы использовал рекурсивную функцию вплоть до листьев. Что-то вроде

function(node n){
    if(n = null)
        return false
    if(function(n.left) or function(n.right) or n.val){
        n.val = true
        return true
    }
    else
        return false
}

Все узлы, помеченные как true, будут вашими узлами в путях от u до v. Время выполнения будет не более (Вершины + Края), поскольку DFS = (V + E) циклы for не более (V) рекурсивные не более (V)

1 голос
/ 17 июня 2010

Запустите DFS со своего начального узла и сохраните свой собственный стек, который сообщает вам, какие узлы вы видели в любой момент времени. Позаботьтесь о циклах: когда вы дважды видели узел, у вас есть цикл, и вы должны прервать свой текущий путь. Старайтесь не посещать родительский узел, чтобы избежать циклов длины 1 (добавьте параметр parent в функцию DFS, это поможет).

Затем, когда вы достигнете узла назначения, выведите содержимое вашего стека.

После завершения DFS у вас будут все пути.

0 голосов
/ 18 июня 2010

вершина находится на пути от A до B, если она достижима от A, и B достижим от нее.

Итак: выполните заливку, начиная с A. Отметьте все эти вершины.выполните заливку, начиная с B и следуя ребрам в обратном порядке.Все отмеченные вершины, которые вы встречаете, являются частью решения.

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