我正在尝试实现Held-Karp算法,以在未加权有向图上找到哈密顿路径。为了实现这一点,我创建了一个内部类Combination,它存储一个表示所采用路径顺序的Stack和一个Set,用于存储当前路径中的元素。
哈密顿路径的定义是仅一次
访问图形中每个顶点的路径我还使用队列来存储该算法尚未完全探索或打折的路径。
最初,此队列填充有组合,每个组合在图中包含一个顶点。这满足了Held-Karp的基本情况,其中平凡的哈密顿路径是通过单个顶点的路径。
当队列不为空时,队列前面的元素将出队。窥视其堆栈中的顶部元素,因为该元素表示添加到路径的最后一个顶点。循环遍历最后一个顶点的相邻顶点,如果其中任何一个不在当前路径集中,则会使用先前的路径Stack和path Set创建一个新的Combination对象,并将新顶点添加到Stack和Set中。将此新的组合对象添加到队列的后面,以供以后分析。如果无法将另一个顶点添加到路径,则循环将继续,并且对该Combination对象的引用将丢失-Combination被打折。
如果在出队时遇到组合对象,且该对象的堆栈长度与图中的顶点数相同,则我们返回该堆栈的数组表示形式,因为它是哈密顿路径。
我正在针对此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之间没有边。