logo search
DM_shpory

34. Гамильтонов цикл в графе. Алгоритм с возвратом для поиска гамильтонова пути. Оценки вычислительной сложности алгоритма.

Цикл, проходящий через все вершины, причем только один раз, и завершающийся в той же точке, называется гамильтоновым циклом. В отличие от эйлеровых путей не известно ни одного простого необходимого и достаточного условия для существования гамильтоновых путей. Не известен так же алгоритм, который проверял бы гамильтоновы пути. В полносвязном графе количество циклов Гамильтона (n-1)! Проблема существования гамильтонова пути принадлежит к классу так называемых NP-полных задач. Это широкий касс задач, включающий фундаментальные задачи из теории графов, логики, теории чисел, дискретной оптимизации и других дисциплин, ни для одной из которых не известен полиномиальный алгоритм (т.е. с числом шагов, ограниченным полиномом от размерности задачи), причем существование полиномиального алгоритма для хотя бы одной из них автоматически влекло бы за собой существование полиномиальных алгоритмов для всех этих задач. Именно факт фундаментальности многих NP-полных задач в различных областях и то, что, несмотря на независимые друг от друга усилия специалистов в этих областях, не удалось найти полиномиального алгоритма ни для одной из этих задач, склоняет к предположению, что такого алгоритма не существует.

Алгоритм. Данные: Граф G = V, E, представленный списками инцидентности ЗАПИСЬ[v], vV. Результаты: Список всех гамильтоновых циклов графа G.

Работу этого алгоритма, так же как и произвольного алгоритма с возвратом, можно проиллюстрировать процессом поиска в некотором дереве. Каждая вершина дерева естественным образом соответствует некоторой последовательности x1, ..., xk, причем вершины, соответствующие последовательностям вида x1, ..., xk, y являются сыновьями этой вершины ( корень соответствует пустой последовательности  ). Рассмотрим полное дерево D, состоящее из всех возможных последовательностей вида x1, ..., xk, где 0  kn и xiAi для 1 ik, и временно допустим, что каждый элемент yAk является допустимым для x1, ..., xk -1, если kn, и ни один элемент не является допустимым для x1, ..., xk -1, если k > n; другими словами, P(x1, ..., xk-1, xk) = истина, если kn, и P(x1, ..., xk-1, xk) = ложь, если kn (xiAi для 1  ik). Тогда нетрудно отметить, что вызов AP(1) вызывает поиск в глубину во всем дереве D (начиная от корня ). Для случая менее тривиальной функции P, определяющей допустимость вершин, процесс поиска опускает рассмотрение вершин поддерева с корнем в каждой встреченной недопустимой вершине, т.е. вершине, соответствующей последовательности x1, ..., xk, для которой P(x1, ..., xk) = ложь). В этом, собственно говоря, заключается эффективность алгоритма с возвратом в отношении полного перебора всех возможностей. Следует отметить, что для большинства приложений число шагов алгоритма с возвратом хотя и будет меньше, чем в случае полного перебора, однако же в наихудшем случае растет по экспоненте с возрастанием размерности задачи. Это справедливо и для случая, если мы ищем только одно, а не все решения (тогда мы просто прерываем выполнение алгоритма после получения первого решения; отметим, что когда задача не имеет решения, эта модификация не влияет на ход выполнения алгоритма).

Алгоритм «в лоб» — это полный перебор всех возможностей: генерируем все n! различных последовательностей вершин и для каждой из них проверяем, определяет ли она гамильтонов путь. Такие действия требуют по меньшей мере n! n шагов, но функция от n подобного вида растет быстрее, чем произвольный многочлен, и даже быстрее, чем произвольная экспоненциальная функция вида an, a > 1, ибо

procedure ГАМИЛЬТ(k)

{генерация всех гамильтоновых циклов, являющихся расширением последовательности X[1], . . ., X[– 1]: массив X — глобальный }

begin

for y Î ЗАПИСЬ [X[– 1]] do

if (k = n +1) and (y = v0) then write(X[1], . . ., X[n], v0)

else if DOP[y] then

begin X[k] := y; DOP[y] := ложь;

ГАМИЛЬТ (k +1);

DOP[y] := истина

end

end; { ГАМИЛЬТ }

begin { главная программа }

for v Î V do DOP[v] := истина; { инициализация }

X[1] := v0; { v0 = произвольная фиксированная вершина графа }

DOP[v0] := ложь;

ГАМИЛЬТ (2);

end.

!!!! для большинства приложений число шагов алгоритма с возвратом хотя и будет меньше, чем в случае полного перебора, однако же в наихудшем случае растет по экспоненте с возрастанием размерности задачи.