3

Given a directed unweighted graph and a set of nodes N, I have to find all the paths of length at most L passing thru all the nodes. Since I am not enforcing each node to be visited only once, you can also call this a walk on the graph.

There are a few problems that can appear related but which did not lead me to any significant progress:

  • Shortest path: the shortest path is not a satisfactory solution since I would like to get all the paths.
  • Steiner tree: in my specific case, due to the graph structure and the properties of the node I need to cover, this will boil down to be the shortest path, but still not solve my problem.
  • Hamiltonian path: this has the additional restriction to visit each vertex exactly once, which is not a property I care about and make the problem much harder.
  • Random walk on the graph: one can image taking a random walk on the graph until the conditions are met but this can be very slow and I would consider that part of the brute force approach. A better heuristic is to compute random spanning trees and then extract the path from there but it does not seem particularly smart as a solution.

I wonder if this is a known problem and there is an algorithm that is not the good old brute force strategy (which I am already doing).

UPDATE: I kept researching and looks like my problem is a more general version of the path enumeration that you can see discusses here. The main difference is that I don't need to count all the paths between a pair of nodes (i,j) but for a larger set of nodes and each path has to pass thru all the nodes.

I would appreciate suggestions on algorithms for this because I don't have much knowledge on the topic.

giz
  • 31
  • 3

1 Answers1

0

Pardon my naivety but I put forward this attempt at a solution.

You wish to find all distinct paths $p$, of length at most $L$, such that $p$ visits every node at least once. Let’s assume we are not working with multigraphs. Formally, a directed graph is a set of nodes $N$ and a set of ordered pairs $E \subseteq N \times N$. A path $p$ is a tuple of edges $(e_0, \ldots, e_n), e_k \in E$ such that for all $0 < i < n$, $src(e_{i + 1}) = tgt(e_i)$.

Impose an arbitrary linear order $<$ on the nodes. This induces a linear order $<'$ on the edges, where for each node $n$, for all edges $(n, n_i)$, $n_i < n_j \implies (n, n_i) < (n, n_j)$.

The set of all paths can be enumerated. Let $f$ be the function which associates each edge with the set of its adjacent edges, $f : E \to \mathcal{P}(E), f(e) = \{n_i, n_j \mid tgt(e) = n_i\}$.

Start at a node with a counter variable at 0 and a set tracking what nodes have been visited, and a set of paths. Visit each connected node, in order. For each visited node, increment the counter by 1 and add the visited node to the tracking set. If every node is visited and the path is not in the set of paths and the count is not greater than $L$, stop and add the path to the set of paths. Else if the counter is greater than $L$, stop.

In Python:


# Assume nodes is a list and edges is a list of tuples

def get_adj_edges(node, edges): adj_edges = [] for e in edges: if e[0] == node: adj_edges.append(e) return adj_edges

def gen_node_with_index(nodes): nodes_with_index = [] for i, node in enumerate(nodes): nodes_with_index.append((i, node))

def order_edges(nodes_with_index, edges): ord_edges = [] for node in nodes_with_index: adj_edges = get_adj_edges(node[1]) # (here, sort adj_edges on the target node’s index) ord_edges += adj_edges return ord_edges

def count_paths(nodes_with_index, ord_edges, length): paths = [] for node in nodes_with_index:

This is unfinished, I tried to make a draft, but it needs revision.