2

This is my algorithm to find a Hamiltonian cycle in a graph:

private SolutionArray solution;
private int V, pathCount;
private int[] path;
private int[][] graph;

/**
 * Constructor
 */
public ConcreteSolver() {
    solution = new SolutionArray();
}

@Override
public SolutionArray solve(PathMatrix input) {

    V = input.getNbVertex();
    path = new int[V];

    /** Set all path to non-visited **/
    boolean[] visited = new boolean[V];
    for (int i = 0; i < V; i++) {
        visited[i] = false;
    }

    Arrays.fill(path, -1);
    graph = input.getMatrix();

    try {
        path[0] = input.getFirstVertex();
        pathCount = 1;

        findPaths(0);

        System.out.println("No solution");
    } catch (Exception e) {

        System.out.println("\nSolution found");
        //input.printMatrix();
        displayAndWrite();
    }

    return solution;

}

/**
 * function to find paths recursively
 */
private void findPaths(int vertex) throws Exception {


    /** solution **/
    if (graph[vertex][0] >= 1 && pathCount == V) {
        throw new Exception();
    }
    /** all vertices selected but last vertex not linked to 0 **/
    if (pathCount == V)
        return;

    for (int v = 0; v < V; v++) {
        /** if connected **/
        if (graph[vertex][v] >= 1) {
            /** add to path **/
            path[pathCount++] = v;

            /** if vertex not already selected solve recursively **/
            if (!isPresent(v))
                findPaths(v);

            /** remove path **/
            path[--pathCount] = -1;

        }

    }

}

/**
 * function to check if path is already selected
 */
private boolean isPresent(int v) {
    for (int i = 0; i < pathCount - 1; i++)
        if (path[i] == v)
            return true;
    return false;
}

I'm able to find a single first Hamiltonian cycle. Is it possible to adapt it to find all possible Hamiltonian cycles found in the graph?

The input is a non-symmetrical matrix (some links between nodes are one way) and some nodes may have 2 or 3 links to other nodes.

Thank you

EDIT:

To clarify, the algorithm can already find a solution but cannot find a second one and so on. From reading, A* using bactracking might solve the issue but I'm not sure if it can be added to what I already have.

JulioQc
  • 310
  • 1
  • 4
  • 20
  • Not so much a comment on your question, but on your implementation: you shouldn't use an Exception to indicate that a solution has been found. Exceptions are to indicate things which are exceptional. See Effective Java 2nd Ed Item 57. You have two outcomes of calling this method: void and Exception. You could easily make this false and true, or an enum NOT_FOUND and FOUND, and it would be much easier to grok. – Andy Turner Nov 12 '15 at 23:52

2 Answers2

1

Currently you have a single array to capture the current path being explored. presumably your displayAndWrite method uses this information to print the solution.

To record all solutions you need to take a copy of the path when you find a hamiltonian cycle.

Somthing like:

private static final int MAX_SOLUTIONS = 100;
private int[][] solutions = new int[MAX_SOLUTIONS][];
private int solutionCount = 0;

private void addSolution(int[] path) {
    if (solutionCount < MAX_SOLUTIONS)
        solutions[solutionCoun++] = Arrays.copyOf(path, path.length);
}

You need to call addSolution in the recursive method where you currently through the exception.

As an aside, throwing an exception to denote success would be considered poor style by nearly all experienced Java coders. I expect the same is true in other languages - exceptions are for exceptions :-)

sprinter
  • 27,148
  • 6
  • 47
  • 78
0

Right now, you throw an Exception when you have detected a cycle:

if (graph[vertex][0] >= 1 && pathCount == V) {
    throw new Exception();
}

Aside from the fact that throwing an Exception is the wrong thing to do here because it is not really an exceptional condition - see my comment on the question - all you need to do is to make the action to take when you have found the cycle less "explosive".

Without knowing the definition of SolutionArray I can't give an answer making use of that.

Since you don't know how many cycles you might find, add a List to gather your solutions:

private List<int[]> solutions = new ArrayList<>();

Now, when you find a solution, just add something to this list - and then return from the method:

if (graph[vertex][0] >= 1 && pathCount == V) {
    solutions.add(java.util.Arrays.copyOf(path, V));
    return;
}

Because this simply returns from the method, rather than throwing an exception, the execution of the calling function continues on to check the next possible path.

It is important that you take a copy of the path, because otherwise you will simply add a reference to the array that you are using as your working copy - so they will all be the same array, and, because you might update it after, will not even necessarily contain a valid solution at the end.

Then, in your main method, just check if this list is non-empty:

if (!solutions.isEmpty()) {
  System.out.println("\nSolution(s) found");
  displayAndWrite();
}
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • That's nice but it doesn't tell me how to detect multiple solutions cycles. Just how to handle them once I find them – JulioQc Nov 13 '15 at 00:12
  • @JulioQc please read my answer carefully and think about the control flow. Specifically, why does your code stop after finding one solution, and why might this not? – Andy Turner Nov 13 '15 at 00:14