4

Undirected Unweighted graph

Having this graph as reference let's say i want the longest path between 0 and 5.

That would be: 0->1->3->2->4->6->5

Is there any good algorithm for this? I've searched and haven't found anything that i was able to understand. I've found plenty algorithms for the shortest path (0->1->2->4->6->5) and i've implemented them successfully. Maybe i'm the problem, but i would like to think otherwise :)

Any help would be welcome

loveMeansNothing
  • 361
  • 1
  • 5
  • 20
  • 1
    Maybe some sort of A* with "inverse" heuristic function? Certainly related to [longest path problem](http://en.wikipedia.org/wiki/Longest_path_problem) but that seems to be concerned with a longest path between _any_ two nodes. – tobias_k Jan 14 '15 at 13:43
  • @tobias_k That's exactly what i want. The longest path between any two nodes – loveMeansNothing Jan 16 '15 at 11:04

1 Answers1

3

This problem is NP-Hard (there is a simple reduction from a Hamiltonian path to your problem, and a Hamiltonian path search is known to be NP-hard). It means that there is no polynomial solution for this problem (unless P = NP).

If you need an exact solution, you can use dynamic programming (with exponential number of states): the state is (mask of visited vertices, last_vertex), the value is true or false. A transition is adding a new vertex which is not in the mask if there an edge between the last_vertex and the new vertex. It has O(2^n * n^2) time complexity, which is still better than O(n!) backtracking.

Here is pseudo code of a dynamic programming solution:

f = array of (2 ^ n) * n size filled with false values
f(1 << start, start) = true
for mask = 0 ... (1 << n) - 1:
    for last = 0 ... n - 1:
        for new = 0 ... n - 1:
            if there is an edge between last and new and mask & (1 << new) == 0:
                f(mask | (1 << new), new) |= f(mask, last)
res = 0
for mask = 0 ... (1 << n) - 1:
    if f(mask, end):
        res = max(res, countBits(mask))
return res

And a little bit more about reduction from Hamiltonian path to this problem:

def hamiltonianPathExists():
    found = false
    for i = 0 ... n - 1:
        for j = 0 ... n - 1:
            if i != j:
                path = getLongestPath(i, j) // calls a function that solves this problem
                if length(path) == n:
                    found = true
    return found

Here is a Java implementation (I did not test properly, so it can contain bugs):

/**
 * Finds the longest path between two specified vertices in a specified graph.
 * @param from The start vertex.
 * @param to The end vertex.
 * @param graph The graph represented as an adjacency matrix.
 * @return The length of the longest path between from and to.
 */
public int getLongestPath(int from, int to, boolean[][] graph) {
    int n = graph.length;
    boolean[][] hasPath = new boolean[1 << n][n];
    hasPath[1 << from][from] = true;
    for (int mask = 0; mask < (1 << n); mask++)
        for (int last = 0; last < n; last++)
            for (int curr = 0; curr < n; curr++)
                if (graph[last][curr] && (mask & (1 << curr)) == 0)
                    hasPath[mask | (1 << curr)][curr] |= hasPath[mask][last];
    int result = 0;
    for (int mask = 0; mask < (1 << n); mask++)
        if (hasPath[mask][to])
            result = Math.max(result, Integer.bitCount(mask));
    return result;
}
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
kraskevich
  • 18,368
  • 4
  • 33
  • 45
  • Is there any java code or pseudo-code of that algorithm? I'm able to understand better with code. "there is a simple reduction from a hamiltonain path to your problem" Are you saying that the only difference between my problem and Hamiltonian's path is that in mine's the last vertex doesn't need to be connected to the initial vertex? – loveMeansNothing Jan 14 '15 at 14:29
  • @loveMeansNothing I have added pseudo code and elaborated on the reduction. – kraskevich Jan 14 '15 at 14:42
  • What if i just want to find the longest path between two vertices? – loveMeansNothing Jan 15 '15 at 17:26
  • 1
    @loveMeansNothing The first code snippet finds the longest path between two vertices. If the question is whether it is possible to do it efficiently, the answer is no(the second code snippet shows that you cannot solve this problem in polynomial time unless P = NP). – kraskevich Jan 15 '15 at 17:28
  • I'm sorry but i can't understand your first code snippet. But that's my problem, i'm pretty sure your code is ok. – loveMeansNothing Jan 15 '15 at 17:33
  • How would getLongestPath(i, j) function look like? – loveMeansNothing Jan 16 '15 at 11:13
  • @loveMeansNothing It the first piece of code, where start = i and end = j. – kraskevich Jan 16 '15 at 11:23
  • If you could give the first algorithm in java or C i would be deeply thankful. I just can't understand that pseudo-code, i've been looking at that for hours and i can't seem, for the sake of me, to understand that. – loveMeansNothing Jan 16 '15 at 11:36
  • 1
    @loveMeansNothing I have added a Java implementation. – kraskevich Jan 16 '15 at 12:01
  • 1
    It might be useful to mention that there is a linear time solution for DAGS. – mrk Jan 16 '15 at 12:14
  • 1
    @saadtaame According to the picture in the question a graph is undirected, so it is not DAG. That's why I decided not to mention it. – kraskevich Jan 16 '15 at 12:16
  • Thanks a lot. I'm getting an ArrayOutOfBoundsException though at: hasPath[mask | (1 << curr)][curr] |= hasPath[mask][last]; Your code literally makes my head explode trying to figure it out. But again, i'm sure i'm the one to blame :P – loveMeansNothing Jan 16 '15 at 12:20
  • @saadtaame i know. But the problem i'm solving only makes sense in a undirected unweighted graph. – loveMeansNothing Jan 16 '15 at 12:22
  • @loveMeansNothing Could you please show the test it fails? I have tested in on an example from your question and a couple of other small tests. It works fine for me. – kraskevich Jan 16 '15 at 12:36
  • You're right, sorry. I've tried it in a matrix[32][32] when i got the ArrayOOBException. Tried it in a smaller graph and it worked fine, i've drawn it to confirm. Is it possible to save the indexes of the vertices for the longest path? – loveMeansNothing Jan 16 '15 at 13:02
  • Maybe also worth mentioning is that `hasPath` can also be a 2D array of vertices, which could store either null or a vertex. In the latter case, if `hasPath[mask][i] == j`, that means there is a path from source to vertex `i` that visits just the vertices masked in `mask`, and the last step taken is the edge from `j` t o`i`. In this way, the whole longest path could be easily constructed. – wlnirvana Mar 11 '21 at 06:03