如何修改这个Held-Karp算法来搜索哈密顿路径而不是循环?

时间:2017-01-06 14:54:07

标签: java algorithm traveling-salesman

我在Wikipedia之后用Java实现了Held-Karp,它为循环的总距离提供了正确的解决方案,但我需要它给我路径(它不会在同一个顶点结束)从哪里开始)。如果我从循环中取出最大重量的边缘,我可以获得路径,但是有可能2个不同的循环具有相同的总距离,但是不同的最大重量,因此其中一个循环是错误的。

这是我的实施:

//recursion is called with tspSet = [0, {set of all other vertices}]

private static TSPSet recursion (TSPSet tspSet) {
    int end = tspSet.endVertex;
    HashSet<Integer> set = tspSet.verticesBefore;

    if (set.isEmpty()) {
        TSPSet ret = new TSPSet(end, new HashSet<>());
        ret.secondVertex = -1;
        ret.totalDistance = matrix[end][0];
        return ret;
    }

    int min = Integer.MAX_VALUE;
    int minVertex = -1;
    HashSet<Integer> copy;

    for (int current: set) {
        copy = new HashSet<>(set);
        copy.remove(current);

        TSPSet candidate = new TSPSet(current, copy);

        int distance = matrix[end][current] + recursion(candidate).totalDistance;

        if (distance < min) {
            min = distance;
            minVertex = current;
        }
    }

    tspSet.secondVertex = minVertex;
    tspSet.totalDistance = min;

    return tspSet;
}

class TSPSet {
    int endVertex;
    int secondVertex;
    int totalDistance;
    HashSet<Integer> verticesBefore;

    public TSPSet(int endVertex, HashSet<Integer> vertices) {
        this.endVertex = endVertex;
        this.secondVertex = -1;
        this.verticesBefore = vertices;
    }
}

2 个答案:

答案 0 :(得分:1)

您可以稍微改变动态编程状态。

让路径从节点S开始。让f(subset, end)成为通过subset中所有顶点并以end顶点结束的路径的最佳成本(Send必须始终在subset)。转换只是使用V边缘添加新的顶点subset而不是end->V

如果您需要结束T的路径,则答案为f(all vertices, T)

旁注:你现在所做的不是动态编程。这是一个详尽的搜索,因为您没有记住子集的答案并最终检查所有可能性(这会导致O(N! * Poly(N))时间复杂度)。

答案 1 :(得分:0)

当前方法的问题

考虑这张图:

enter image description here

访问所有顶点(每个顶点一次)的最短路径长度为3,但最短周期为1 + 100 + 200 + 300,即使您移除了最大权重边缘也是301.

换句话说,通过从最短周期删除边来构造最短路径是不正确的。

建议的方法

将循环算法转换为路径算法的另一种方法是向图中添加一个新节点,该节点对所有其他节点都有零成本边缘。

原始图中的任何路径都对应于此图中的一个循环(路径的起点和终点是额外节点连接的节点。