Алгоритм гамильтонова пути на направленном невзвешенном графе использует несуществующие ребра
Я пытаюсь реализовать алгоритм Хелда-Карпа для нахождения гамильтонова пути на невзвешенном ориентированном графе. Для этого я создал внутренний класс Combination, в котором хранится стек, представляющий порядок выбранного пути, и набор, в котором хранятся элементы, находящиеся в данный момент на пути.
Определение гамильтонова пути - это путь, который посещает каждую вершину графа только один раз.
Я также использую очередь для хранения путей, которые еще не были полностью исследованы или не учтены алгоритмом.
Первоначально эта очередь заполняется комбинациями, каждая из которых содержит одну вершину в графе. Это удовлетворяет базовому случаю Хелда-Карпа, где тривиальный гамильтонов путь - это путь, который проходит через одну вершину.
Пока очередь не пуста, элемент с начала очереди удаляется. Верхний элемент из его стека просматривается, так как этот элемент представляет последнюю вершину, добавленную к пути. Смежные вершины последней вершины проходят через петлю, и если какая-либо из них не находится в текущем наборе пути, создается новый объект Combination с предыдущим путем Stack и путем Set, и новая вершина добавляется в Stack и Set. Этот новый объект комбинации добавляется в конец очереди для последующего анализа. Если невозможно добавить еще одну вершину к пути, цикл продолжается и ссылка на этот объект комбинации теряется - комбинация сбрасывается.
Если при снятии очереди мы сталкиваемся с комбинированным объектом со стеком, длина которого равна числу вершин в графе, тогда мы возвращаем представление массива этого стека, поскольку это гамильтонов путь.
Я проверяю этот алгоритм на этом графике.
Список смежности, сгенерированный моим кодом для этого графика, приведен ниже:
[[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);
}
}
Идентификаторы HashMap - это просто отображение целочисленных идентификаторов вершин и их фактических значений String.
Поскольку этот граф не содержит гамильтонова пути, я ожидаю, что на выходе будет массив нулевых строк. Однако вывод, который я на самом деле получаю:
F -> A -> B -> D -> C -> E
Что очень странно, поскольку нет грани между B и D на графике или в матрице.