我正在尝试实现 Held-Karp 算法以在未加权的有向图上找到哈密顿路径。为了实现这一点,我创建了一个内部类 Combination ,它存储一个 Stack ,它表示所采用的路径的顺序,以及一个 Set ,它存储当前在路径中的元素。
哈密顿路径的定义是只访问图中每个顶点一次的路径
我还使用队列来存储算法尚未完全探索或折扣的路径。
最初,这个队列充满了组合,每个组合在图中都包含一个顶点。这满足了 Held-Karp 的基本情况,其中平凡的哈密顿路径是通过单个顶点的路径。
当队列不为空时,队列前面的元素被出列。其堆栈中的顶部元素被窥视,因为该元素表示添加到路径的最后一个顶点。循环遍历最后一个顶点的相邻顶点,如果其中任何一个不在当前路径集中,则使用先前的路径 Stack 和路径 Set 创建一个新的 Combination 对象,并将新顶点添加到 Stack 和 Set 中。这个新的组合对象被添加到队列的后面以供以后分析。如果无法将另一个顶点添加到路径,则循环继续并且对此组合对象的引用丢失 - 组合被打折。
如果在出队时我们遇到一个具有与图中顶点数相同长度的 Stack 的 Combination 对象,那么我们返回该 Stack 的数组表示,因为它是哈密顿路径。
我正在针对这个Graph测试这个算法。
我的代码为此图生成的邻接列表如下:
[[1], [2, 3], [4], [4], [5], []]
矩阵索引和顶点值之间的键映射是:
{0=F, 1=A, 2=B, 3=D, 4=C, 5=E}
public String[] getHamiltonianPath() {
String hamiltonianPath[] = new String[adjacencyList.size()];
Combination newCombination;
for(int i = 0; i < adjacencyList.size(); i++) {
LinkedList<Combination> combinations = new LinkedList<>();
// create base case with paths of length 1 including only a single vertex.
for(int j = 0; j < adjacencyList.size(); j++) {
combinations.add(new Combination(j));
}
while(!combinations.isEmpty()) {
Combination current = combinations.pollFirst();
// If we've found a Hamiltonian Path return it.
if(current.pathOrder.size() == adjacencyList.size()) {
while(!current.pathOrder.isEmpty()) {
hamiltonianPath[current.pathOrder.size() - 1] = ids.get(current.pathOrder.pop());
}
return(hamiltonianPath);
}
// Select the last vertex added to the path
int lastVertex = current.pathOrder.peek();
// Get all the vertices adjacent to the last vertex added to the path
HashSet<Integer> neighbours = adjacencyList.get(lastVertex);
for(int neighbour : neighbours) {
// Create a new combination for each path that includes the previous path
// and is extended to one of the adjacent vertices to the last vertex added.
newCombination = new Combination(current.path, current.pathOrder);
// Check if the adjacent vertex is already on the path.
// If so do not add it to the path
if(!newCombination.path.contains(neighbour)) {
newCombination.path.add(neighbour);
newCombination.pathOrder.push(neighbour);
// Add the new combination to the combinations queue
// for further extension later
combinations.add(newCombination);
}
}
}
}
return(hamiltonianPath);
}
public class Combination {
HashSet<Integer> path;
Stack<Integer> pathOrder;
public Combination(HashSet<Integer> path, Stack<Integer> pathOrder) {
this.path = path;
this.pathOrder = pathOrder;
}
public Combination(int origin) {
path = new HashSet<>();
pathOrder = new Stack<>();
path.add(origin);
pathOrder.push(origin);
}
}
ids HashMap 只是顶点的整数 ID 与其实际 String 值之间的映射。
由于该图不包含哈密顿路径,我希望输出是一个空字符串数组。但是我实际得到的输出是:
F -> A -> B -> D -> C -> E
这很奇怪,因为在图形或矩阵中 B 和 D 之间没有边。