Cykl Hamiltona, to taki cykl w grafie, który zawiera wszystkie
wierzchołki grafu, przy czym każdy dokładnie raz.
Problem znajdowania cyklu
Hamiltona jest jednak znacznie trudniejszy niż w znajdowania cyklu Eulera. Nie
istnieje algorytm działający w sensownym czasie, który potrafi znaleźć cykl
Hamiltona w dowolnym grafie.
Żeby znaleźć cykl Hamiltona w grafie należy zapuścić rekurencję
z nawrotami do znajdowania wszystkich cykli (bez powtarzających się
wierzchołków), a po znalezieniu jakiegoś cyklu sprawdzamy czy zawiera wszystkie
wierzchołki. Niektórym to już mówi wszystko, a tym którym nie mówi to tłumaczę
dalej.
Zaczynamy szukać drogę w jakimkolwiek wierzchołku, nazwijmy go
s. Załóżmy, że w pewnym momencie wykonywania algorytmu doszliśmy do
wierzchołka v. Mamy zapamiętane wierzchołki "użyte" do przejścia drogą z
s do v, z oboma tymi wierzchołkami włącznie (uwaga: możliwe, że w
v znajdziemy się kilkakrotnie i za każdym razem dojdziemy tam inną drogą
z s). Dalej przechodzimy z v rekurencyjnie do jego następników
(albo sąsiadów w przypadku grafów nieskierowanych), ale tylko tych nieużytych
(zaznaczając je jako już użyte). Gdy obejrzymy wszystkie następniki v i
nic nam to nie da, to musimy wrócić (rekurencyjnie) oraz !odznaczyć! wierzchołek
v, żeby w przyszłości można było ponownie przez niego przejść. Jeżeli w
pewnym momencie z jakiegoś wierzchołka będie można przejść bezpośrednio do
s to znaleźliśmy pewien cykl i musimy sprawdzić czy odwiedziliśmy
wszystkie wierzchołki; jeśli tak to cykl jest hamiltonowski i możemy go wypisać,
a jeśli nie to z powrotem i szukamy dalej.
Żeby móc sprawdzić czy znaleziony
cykl jest hamiltonowskim wystarczy jedynie zliczać odwiedzone wierzchołki.
Należy przy każdym zagłębieniu rekurencji zwiększyć jakiś licznik o 1, a przy
powrocie zmniejszyć go o 1. Jeśli zrobimy cykl od s do s to jest
on cyklem Hamiltona gdy licznik ma wartość równą liczbie wierzchołków w grafie
(bo wtedy odwiedzone zostały wszystkie wierzchołki).
No to (pseudo)kod. Funkcja HamiltonCycle zwróci True jeżeli cykl Hamiltona zostanie znaleziony oraz w tablicy H znajdą się kolejne wierzchołki tego cyklu; w przeciwnym wypadku funkcja zwróci False.
{
N - liczba wierzcholkow
D[1..N] - tablica logiczna odwiedzin wierzcholkow
H[1..N] - tablica kolejnych wierzcholkow cyklu Hamiltona
}
function PathRec(v: Integer): Boolean;
{fun. rekurencyjnego znajdowania cykli od s do s}
begin
D[v]:=True; {zaznczanie wierzcholka jako uzyty}
Inc(used); {zwiekszenie liczby uzytych wierzcholkow}
PathRec:=True;
for i:=Successor(v) do {petla po nastepnikach wierzch. v}
begin
if i=s then {jesli zrobilismy cykl ...}
if used=N then {jesli do tego wszystkie wierzcholki uzyte}
begin
H[1]:=v;
Exit; {wtedy wychodzi z wartoscia True}
end;
if not D[i] then {jesli wierzch. i jest nieuzyty ...}
if PathRec(i) then
{przechodzimy rek. do wierzcholka i jesli znalezlismy tam cykl H. ...}
begin
H[No]:=v; {wstawiamy kolejny wierzcholek do tablicy H}
Inc(No);
Exit; {wychodzi z wartoscia True}
end;
end;
PathRec:=False; {nie tedy droga, trza zwrocic False}
D[v]:=False; {zaznczanie wierzcholka jako nieuzyty}
Dec(used); {zmniejszenie liczby uzytych wierzcholkow}
end;
function HamiltonCycle: Boolean;
begin
for i:=1 to N do
D[i]:=False; {oznaczamy wszystkie wierzcholki jako nieuzyte}
used:=0; {zmienna potrzebna do liczenia przebytych wierzcholkow}
No:=2; {zmienna potrzebna do wpisywania wierzcholkow cyklu do tablicy H}
s:=1; {wierzcholek startowy - calkowicie dowolny z przedzialu 1..N}
HamiltonCycle:=PathRec(s);
end;
A tutaj niespodzianka. Algorytm by najmniej nie działa w czasie
O(E).
Problem znajdowania cyklu Hamiltona w grafie jest NP-zupełny (w dodatku
silnie NP-zupełny), co oznacza tyle, że nie istnieje algorytm rozwiązujący ten
problem działający w czasie wielomianowym. I rzeczywiście - algorytm, który
podałem działa pesymistycznie w czasie O(V!), co zalicza się do czasów
wykładniczych (możliwe, że dla przeciętnych grafów działa to lepiej). Skutek
tego jest straszny: dla grafów dwudziestoparowierzchołkowych (no, może trochę
więcej - nie wiem) algorytm zacznie wymiękać czasowo.