在部分定向图中查找所有可能的哈密顿周期

时间:2015-11-12 23:17:37

标签: java hamiltonian-cycle

这是我在图中找到哈密顿循环的算法:

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;
}

我能找到一个第一个汉密尔顿循环。是否有可能对其进行调整以找到图中找到的所有可能的哈密顿循环?

输入是非对称矩阵(节点之间的某些链路是单向的),并且一些节点可能具有到其他节点的2或3个链路。

谢谢

编辑:

为了澄清,该算法已经可以找到解决方案,但找不到第二个,依此类推。从阅读,A *使用bactracking可以解决问题,但我不确定它是否可以添加到我已有的。

2 个答案:

答案 0 :(得分:1)

目前,您有一个数组来捕获正在探索的当前路径。大概是您的displayAndWrite方法使用此信息来打印解决方案。

要记录所有解决方案,您需要在找到哈密顿循环时复制路径。

像:

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);
}

您需要在当前通过异常的递归方法中调用addSolution

顺便说一下,几乎所有有经验的Java程序员都会认为抛出一个表示成功的例外。我希望在其他语言中也是如此 - 异常例外: - )

答案 1 :(得分:0)

现在,当您检测到一个循环时,您会抛出异常:

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

除了抛出异常是错误的事情,因为这不是一个特殊的条件 - 请参阅我对这个问题的评论 - 你需要做的就是在你找到的时候采取行动周期较少&#34;爆炸&#34;。

在不知道SolutionArray的定义的情况下,我无法回答这个问题。

由于您不知道可能会找到多少个周期,因此请添加List来收集解决方案:

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

现在,当您找到解决方案时,只需在此列表中添加内容 - 然后从方法返回:

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

因为这只是从方法返回,而不是抛出异常,所以继续执行调用函数来检查下一条可能的路径。

重要的是你要获取路径的副本,因为否则你只需添加一个对你正在使用的数组的引用作为你的工作副本 - 所以它们都将是同一个数组,因为你可能会更新它之后,甚至不一定包含最终的有效解决方案。

然后,在main方法中,只需检查此列表是否为非空:

if (!solutions.isEmpty()) {
  System.out.println("\nSolution(s) found");
  displayAndWrite();
}