Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

algorithm to enumerate all possible paths

Consider the following graph:

alt text

I'm trying to find a way to enumerate all possible paths from a source node to a target node. For example, from A to E, we have the following possible paths:

A B C D E
A B C E
A C D E
A C E

Note that for A C D E, there are actually 2 paths, since one of the paths uses edge F3 and the other uses edge F5. Also, since there's a cycle between A and C, you could end up with an infinite number of paths, but for the purposes of this I'm only interested in paths in which no node is repeated on the path from source to target.

I wrote a depth first search (DFS) algorithm, but the problem is that when you have multiple edges between 2 nodes (like edges F3 and F5 above) I'm not sure how to handle it. My algorithm only brings back paths A C D E and A C E, not the other paths. In the case of A B C E, I understand the reason, because it starts at A and then goes to C and builds those paths, but when the DFS gets back to node B, it then tries to go to C, but C has already been visited so it stops.

Anyway, I just wondered if there was a way to do this, or maybe this is NP-complete.

In case you'd like to see my DFS, code is below (sorry for the macro abuse, I use these in contest programming so it's a bit of a habit).

#include <algorithm>
#include <numeric>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cassert>
#include <cmath>
#include <complex>
#include <stack>
#include "time.h"
using namespace std;
#define SZ(x) (int)x.size()
#define FOR(i,x,y) for(int i=(int)(x);i<=(int)(y);++i)
#define REP(i,n) FOR(i,0,n-1)
#define FORD(i,x,y) for(int i=(int)(x);i>=(int)(y);--i)
#define ALL(a) (a).begin(),(a).end()
#define FORE(i,t) for(i=t.begin();i!=t.end();++i)
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<bool> VB;
typedef vector<double> VD;
typedef deque<int> DI;
typedef deque<string> DS;
typedef long long i64;
#define PI 3.14159265358979323
#define DEGTORAD(x) (double)x * 3.14159265358979323846264338327950288 / 180.0
#define RADTODEG(x) (double)x * 180 / 3.14159265358979323846264338327950288
#define prt if(1)printf
template <typename T> string tostr(const T& t) { ostringstream os; os<<t; return os.str(); } 

typedef pair< char, char > PCC;
map< PCC, int > adj;
map< char, bool > vis;

vector< char > path;

void dfs(char at) {
  if (at == 'E') {
    REP(i,SZ(path)) {
      if (i != 0)
        cout<<",";
      cout<<path[i];
    }
    cout<<",E"<<endl;
    return;
  }
  if (vis[at])
    return;
  vis[at] = true;
  map< PCC, int >::iterator it;
  FORE(it,adj) {
    if (it->first.first == at) {
      path.push_back(it->first.first);
      dfs(it->first.second);
      path.erase(path.end()-1);
    }
  }
}


int main() {
  adj[make_pair('A','B')] = 1;
  adj[make_pair('A','C')] = 1;
  adj[make_pair('C','D')] = 1;
  adj[make_pair('D','E')] = 1;
  adj[make_pair('E','I')] = 1;
  adj[make_pair('C','F')] = 1;
  adj[make_pair('F','G')] = 1;
  adj[make_pair('F','H')] = 1;
  adj[make_pair('C','E')] = 1;
  dfs('A');
  return 0;
}

Output:

---------- Capture Output ----------
A,C,D,E
A,C,E
like image 888
dcp Avatar asked Oct 12 '10 12:10

dcp


People also ask

Does Dijkstra find all paths?

Dijkstra's Algorithm finds the shortest path between a given node (which is called the "source node") and all other nodes in a graph. This algorithm uses the weights of the edges to find the path that minimizes the total distance (weight) between the source node and all other nodes.

How do I get all the paths from a dag?

Finding all the possible paths in any graph in Exponential. It can be solved by using Backtracking. For DAG's we can do it using Depth first search(DFS). In DFS code, Start at any node, Go to the extreme dead end path and note down all the nodes visited in that path using some array or list.

Which algorithm will you use to determine the path from the source to the destination?

A global routing algorithm computes the least cost path between a source and destination using complete, global knowledge about the network. That is, the algorithm takes the connectivity between all nodes and all links costs as inputs.


2 Answers

Anyway, I just wondered if there was a way to do this, or maybe this is NP-complete.
I don't believe you can output n! possible paths in polynomial time. And that's how may you get if each node is connected to each other node.

but the problem is that when you have multiple edges between 2 nodes (like edges F3 and F5 above)
So, you want to consider edges F3 and F5 to be the same, right? It's probably the simplest option to just remove duplicate edges before you call dfs, then.

because it starts at A and then goes to C and builds those paths, but when the DFS gets back to node B, it then tries to go to C, but C has already been visited so it stops.
Well, let's mark C as not visited again, then.

void dfs(char at) {
    vis[at] = true;

    // do stuff with 'at'

    vis[at] = false;
}
like image 73
Nikita Rybak Avatar answered Sep 25 '22 02:09

Nikita Rybak


Here is how you can do it with BFS: the following (python) functions (modified BFS with a recursive path-finding function between two nodes) can be used to find all possible paths between two nodes in an acyclic graph:

from collections import defaultdict

# modified BFS
def find_all_parents(G, s):
    Q = [s]
    parents = defaultdict(set)
    while len(Q) != 0:
        v = Q[0]
        Q.pop(0)
        for w in G.get(v, []):
            parents[w].add(v)
            Q.append(w) 
    return parents

# recursive path-finding function (assumes that there exists a path in G from a to b)   
def find_all_paths(parents, a, b): 
    return [a] if a == b else [y + b for x in list(parents[b]) for y in find_all_paths(parents, a, x)]

For example, with the following graph (DAG) G (by removing the directed cycles and multi-edges from the given graph), given by

G = {'A':['B','C'], 'B':['C'], 'C':['D', 'E', 'F'], 'D':['E'], 'E':['I'], 'F':['G', 'H']}

if we want to find all paths between the nodes 'A' and 'E' (using the above-defined functions as find_all_paths(find_all_parents(G, 'A'), 'A', 'E')), it will return the following paths, as desired:

# ACDE
# ABCDE
# ACE
# ABCE

enter image description here

like image 38
Sandipan Dey Avatar answered Sep 24 '22 02:09

Sandipan Dey