cykle Hamiltona i Eulera


Ćwiczenie numer: 4 Data oddania ćwiczenia:

Temat: Cykle Eulera i Hamiltona

Cykl Eulera.

Cyklem Eulera w grafie nazywamy cykl, który przechodzi przez każdą krawędź dokładnie jeden raz (chociaż może wielokrotnie odwiedzać ten sam wierzchołek). Spójny graf skierowany ma cykl Eulera wtedy i tylko wtedy, gdy stopień wejściowy każdego wierzchołka v jest równy jego stopniowi wyjściowemu .

0x08 graphic
Przykład:

Zasada działania algorytmu.

procedure cykl_eulera(v:byte);

var

x,u,j,i:integer;

begin

for i:=1 to n do begin ce[i]:=0; stos[i]:=0; end;

i:=1;

j:=1;

stos[1]:=v;

while stos[1]<>0 do

begin

i:=1;

while stos[i]<>0 do i:=i+1;

v:=stos[i-1];

x:=za(v);

if X<>0 then

begin

u:=x;

stos[i]:=u;

tab[v,u]:=0;

tab[u,v]:=0;

v:=u;

end

else

begin

v:=stos[i-1];

stos[i-1]:=0;

ce[j]:=v;

j:=j+1;

y1:=j;

end;{od else}

end;{od while}

end;

Jako pierwszy element na stosie umieszczany jest dowolny wierzchołek z grafu ( w tym przypadku wierzchołek o numerze 1). Następnie pętla while tak długo zwiększa i aż stos[i] będzie równy zero tzn. znajdować się będzie na szczycie stosu. Później na stosie umieszczane są kolejne wierzchołki z listy ZA[v] (gdzie v jest szczytowym elementem stosu) a krawędzie są usuwane z grafu. Proces ten trwa tak długo aż lista ZA[v] będzie równa 0. Wówczas cały graf zostaje usunięty z reprezentacji, a wszystkie jego wierzchołki znajdują się na stosie. Kolejnym krokiem algorytmu jest przepisanie zawartości stosu do tablicy CE, która zawiera wynik, czyli wierzchołki ułożone w odpowiedniej kolejności , które należy aby otrzymać cykl Eulera. Złożoność tego algorytmu wynosi O(m), gdzie m jest liczbą wierzchołków. Jednak czas wykonywania jest wykładniczy, ponieważ graf o wypełnieniu np. 100% ma (n*(n-1))/2 krawędzi które algorytm musi przejść.

Cykl Hamiltona.

0x08 graphic
Cykl Hamiltona w grafie nieskierowanym G=(V,E) to cykl prosty zawierający wszystkie wierzchołki zbioru V. W cyklu tym każdy wierzchołek odwiedzany jest tylko jeden raz oraz wierzchołkiem początkowym i końcowym jest ten sam wierzchołek. W grafie może być wiele cykli ale są też grafy, które nie zawierają cykli. Problem "czy graf ma cykl Hamiltona" jest problemem NP - zupełnym co oznacza, że sprawdzenie czy dany graf ma cykl Hamiltona czy też nie jest bardzo trudne i niewykonalne w czasie wielomianowym.

0x08 graphic

Zasada działania algorytmu

procedure hamilton(k:integer);

var i,y,w :integer;

begin

if jest_ham then

repeat

y:=za(x[k-1]);

if y=0 then break;

if (k=n+1) and (y=start) then

begin

for i:=1 to n do write(x[i]);

jest_ham:=false;

end

else

if dop[y] then

begin

x[k]:=y;

dop[y]:=false;

hamilton(k+1);

dop[y]:=true;

indeks[y]:=1;

Działanie tego algorytmu można przedstawić jako proces przeszukiwania pewnego drzewa. Każdy wierzchołek drzewa odpowiada odpowiedniemu ciągowi . Rozważmy pełne drzewo D złożone ze wszystkich możliwych ciągów postaci<x1,...,xk>, gdzie 0<=k<=n i xi∈Ai dla 1<=i<=k , oraz załóżmy chwilowo, że każdy element nie jest dopuszczalny dla <x1,...xk-1>, jeśli k>n.

true jeśli k<=n

P(x1,...,xk-1,xk)=

false jesli k>n

Wywołanie dla pierwszego wierzchołka spowoduje przeszukanie w głąb całego drzewa D. W przypadku funkcji P określającej dopuszczalność wierzchołków proces przeszukiwania "opuszcza" rozpatrywanie tych wierzchołków poddrzewa o korzeniu w każdym napotkanym wierzchołku "niedopuszczalnym" (tzn. odpowiadającym ciągowi <x1,...,xk>, dla którego P (x1,..xk)=false). Na tym właśnie polega efektywność algorytmu z powracaniem w stosunku do pelnego przeglądu wszystkich możliwości.

Kod programu


program cycle;

uses dos,crt;

const m=50; {max tablicy}

krok=4;

wypelnienie=80;

b=1;{0 czytanie z pliku 1 losowanie}

type e_stos=record

poczatek,koniec:byte;

end;

var tab :array [1..m,1..m] of byte; {mac.sasiedztwa}

stos:array [1..(m*m*2)] of byte;

x:array [1..m] of byte;

ce:array [1..m*m] of byte; {stos z wierzcholkami z cyklu eulera}

indeks:array [1..m] of byte; {wektor przesuniec m.s.}

dop:array[1..m] of boolean; {czy wieszcholek odw}

y1,start,n:integer;

poczatek,koniec,wynik_h,wynik_e:real;

f,source:text;

jest_ham:boolean;

h,k3,k2,k,i,j:word;

Function WlaczTimer :LongInt;

Var Reg :Registers;

Znacznik :Byte;

Begin

Znacznik:=0;

Reg.AH:=$83;

Reg.AL:=0;

Reg.CX:=$7FFF;

Reg.DX:=$FFFF;

Reg.BX:=Ofs(Znacznik);

Reg.ES:=Seg(Znacznik);

Intr($15,Reg);

WlaczTimer:=$7FFFFFFF;

End;

Function WylaczTimer :LongInt;

Var Reg :Registers;

Begin

WylaczTimer:=MemL[$0040:$009C];

Reg.AH:=$83;

Reg.AL:=1;

Intr($15,Reg);

End;

Function CzasWykonania :Real;

Var Czas :Real;

Begin

Czas:=(Poczatek-koniec);

CzasWykonania:=Czas;

End;

procedure losuj(wyp:byte);

var temp,z,p,q:byte;

begin

if b=1 then

begin

for p:=1 to m do

for q:=p to m do

begin

z:=random(100);

if wyp >= z then

begin

temp:=random(10);

tab[p,q]:=temp;

tab[q,p]:=temp;

end

else

begin

tab[p,q]:=0;

tab[q,p]:=0;

end;

end;

for p:=1 to m do tab[p,p]:=0;

end

else

begin

assign(source,'grafh.txt');

reset(source);

readln(source,n);

for p:=1 to n do

for q:=1 to n do

read(source,tab[p,q]);

end;

end;

procedure wyswietl;

var

i,j:byte;

begin

for i:=1 to n do

begin

for j:=1 to n do write(tab[j,i]:3);

writeln;

end;

end;

function ZA(nr:integer):integer;

label 5;

var

l:integer;

begin

if indeks[nr]<>0 then {macierz sasiedztwa}

begin

if indeks[nr]<=n then

while tab[nr,indeks[nr]]=0 do

begin

indeks[nr]:=indeks[nr]+1;

if indeks[nr]>n then goto 5;

end

else goto 5;

za:=indeks[nr];

indeks[nr]:=indeks[nr]+1;

end

else

5:

begin

indeks[nr]:=0;

za:=0;

end;

end;

function sprawdz:boolean;

var i,j,licznik,licznik2:byte;

begin

licznik2:=0;

sprawdz:=true;

for i:=1 to n do

begin

licznik:=0;

for j:=1 to n do

begin

if tab[i,j]<>0 then licznik:=licznik+1;

end;

if licznik mod 2 <>0 then

begin

licznik2:=licznik2+1;

if licznik2>2 then

begin

sprawdz:=false;

break;

start:=1

end

else

start:=i;

sprawdz:=true;

end;

end;

end;

procedure cykl_eulera(v:byte);

var

x,u,j,i:integer;

begin

for i:=1 to n do begin ce[i]:=0; stos[i]:=0; end;

i:=1;

j:=1;

stos[1]:=v;

while stos[1]<>0 do

begin

{ for j:=1 to n do indeks[j]:=1;}

i:=1;

while stos[i]<>0 do i:=i+1;

v:=stos[i-1];

x:=za(v);

if X<>0 then

begin

u:=x;

stos[i]:=u;

tab[v,u]:=0;

tab[u,v]:=0;

v:=u;

end

else

begin

v:=stos[i-1];

stos[i-1]:=0;

ce[j]:=v;

j:=j+1;

y1:=j;

end;{od else}

end;{od while}

end;

procedure hamilton(k:integer);

var i,y,w :integer;

begin

if jest_ham then

repeat

y:=za(x[k-1]);

if y=0 then break;

if (k=n+1) and (y=start) then

begin

{ for i:=1 to n do write(x[i]);}

jest_ham:=false;

end

else

if dop[y] then

begin

x[k]:=y;

dop[y]:=false;

hamilton(k+1);

dop[y]:=true;

indeks[y]:=1;

end;

until false;

end;

procedure start_ham;

var i:byte;

begin

for i:=1 to n do dop[i]:=true;

x[1]:=start;

dop[start]:=false;

hamilton(2);

end

{*******************}

{ Program glowny }

{*******************}

begin

randomize;

clrscr;

Assign(f,'c:\niekaso.wac\moje\algorytm\cykle\cykle2.txt');

rewrite(f);

poczatek:= WlaczTimer;

koniec:=wylaczTimer;

n:=krok;

k3:=0;

k:=1;

wynik_e:=0;

wynik_h:=0;

repeat

wynik_h:=0;

start:=1;

for h:=1 to 100 do

begin

losuj(wypelnienie);

for j:=1 to n do indeks[j]:=1;

jest_ham:=true;

poczatek:= WlaczTimer;

start_ham;

koniec:=wylaczTimer;

wynik_h:=wynik_h+czaswykonania;

end;

writeln;

writeln('Cykl Hamiltona dla ',n,' wierzcholkow czas wyk (suma 100 pomiarow): ',wynik_h/1000000:8:5);

wynik_e:=0;

for h:=1 to 100 do

begin

start:=1;

losuj(wypelnienie);

sprawdz;

for j:=1 to n do indeks[j]:=1;

poczatek:= WlaczTimer;

cykl_eulera(start);

koniec:=wylaczTimer;

{ if sprawdz then for i:=1 to y1-1 do write(ce[i]:3);}

wynik_e:=wynik_e+czaswykonania;

end;

writeln;

writeln('Cykl eulera dla ',n,' wierzcholkow czas wyk (suma 100 pomiarow): ',wynik_e/1000000:8:5);

writeln(f,n:10,wynik_e:20:0,wynik_h:20:0);

n:=n+krok;

{if k3 mod 100 =0 then

begin

if (k=1)and(k2=1) then begin gotoxy(75,1); write('|'); k:=2; k2:=0; end;

if (k=2)and(k2=1) then begin gotoxy(75,1); write('/'); k:=3; k2:=0; end;

if (k=3)and(k2=1) then begin gotoxy(75,1); write('-'); k:=4; k2:=0; end;

if (k=4)and(k2=1) then begin gotoxy(75,1); write('|'); k:=5; k2:=0; end;

if (k=5)and(k2=1) then begin gotoxy(75,1); write('\'); k:=1; k2:=0; end;

k2:=1;

end;

k3:=k3+1;

end;}

until m<n;

close(f);

writeln('********KONIEC********');

sound(1000);

delay(100);

nosound;

end.


Tabela pomiarów i wykresy

wypełnienie 70%

liczba wierzchołków

cykl Eulera

cykl Hamiltona

[-]

[s]

[s]

5

0.10150

0.10346

10

0.10541

0.12493

15

0.12981

1.95688

20

0.16104

1.03651

25

0.25669

0.14347

30

0.42261

0.27426

35

0.67539

0.49190

40

1.08238

0.19130

45

1.65432

0.26938

50

2.45757

0.42554

wypełnienie 80%

liczba wierzchołków

cykl Eulera

cykl Hamiltona

[-]

[s]

[s]

5

0.10150

0.10053

10

0.10834

0.11419

15

0.13274

0.11810

20

0.19130

0.16494

25

0.30354

0.13762

30

0.50264

0.16006

35

0.85010

0.14347

40

1.37226

0.17080

45

2.12378

0.18934

50

3.13882

0.21277

wypełnienie 100%

liczba wierzchołków

cykl Eulera

cykl Hamiltona

[-]

[s]

[s]

5

0.10053

0.10053

10

0.11517

0.10931

15

0.13371

0.11029

20

0.24107

0.11712

25

0.40211

0.12200

30

0.71248

0.12200

35

1.21512

0.14933

40

2.00958

0.16397

45

3.13003

0.19520

50

4.69261

0.20886

0x08 graphic

0x08 graphic

0x08 graphic

0x08 graphic

Wnioski.

Ze względu na niedokładność pomiaru czasu za pomocą funkcji, której używałem zdecydowałem, że czasy podane w tabeli i na wykresach są czasami sumarycznymi 100 kolejnych pomiarów .Równocześnie taka forma pomiarów jest uśrednieniem pomiarów i eliminuje nietypowe dane wejściowe grafu .

Jak można zaobserwować na wykresach zachowanie się obu algorytmów znacznie się od siebie różni. Algorytm wyznaczający cykl Eulera jest algorytmem bardzo stabilnym, i wraz ze wzrostem wypełnienia grafu rośnie czas wyznaczenia cyklu, co się ściśle wiąże z liczbą krawędzi w grafie. Jednak jego charakterystyka jest wykładnicza co jest spowodowane tym, że liczba krawędzi jest równa w przybliżeniu (n*n)/2 . Wydawałoby się, że algorytm ten powinien mieć złożoność rzędu n ale w rzeczywistości musi on sprawdzić i przejść (n*n)/2 krawędzi. Algorytm ten jest bardzo stabilny i kształt charakterystyki czasowej jest zawsze taki sam nie zależnie od wypełnienia co jest niewątpliwie dużym plusem tego algorytmu.

Przeciwieństwem stabilności jaką prezentuje algorytm cyklu Eulera jest algorytm cyklu Hamiltona. Spowodowane jest to tym, że algorytm ten jest algorytmem klasy NP - zupełnej. Przy prawidłowej konfiguracji grafu czyli takiego, który zawiera cykl algorytm ten jest bardzo szybki, ponieważ buduje sobie drzewo, które przeszukuje odznaczając sobie drogi, w których na pewno nie ma cyklu. Taka metoda jest bardzo efektywna i nie wymaga n! porównań jak w przypadku poszukiwania rozwiązania metodą porównywania wszystkich kombinacji wierzchołków.

Z wykresów można zaobserwować, że dla wypełnienia 100% algorytm wyszukujący cykl Hamiltona jest bardzo stabilny i znacznie szybszy od algorytmu wyszukującego cykl Eulera. Jednak wraz ze spadkiem wypełnienia algorytm Hamiltona zachowuje się coraz mniej stabilnie co bardzo wyraźnie widać przy wypełnieniu 70%. Przy wypełnieniu 50%, którego wykresu nie zamieściłem w tym sprawozdaniu czas poszukiwania cyklu w niektórych przypadkach sprawiał wrażenie takiego jakby dążyłby do nieskończoności co potwierdza tezę, że sprawdzenie czy dany graf posiada cykl Hamiltona jest problemem NP - zupełnym. Nasuwa się z tego praktyczny wniosek taki, że przy rzadkim wypełnieniu grafu znalezienie w nim cyklu Hamiltona może być bardzo złożone obliczeniowo lub niewykonalne chyba, że przeprowadzimy bardzo dużo losowań grafu.

Praktyczne zastosowanie cyklu Hamiltona

Cykl ten może być wykorzystywany jako algorytm wyszukujący drogę przebiegającą przez wszystkie miasta , które są odwiedzane tylko jeden raz lub też w sieciach komputerowych do budowania sieci typu BNC, gdzie połączenie pomiędzy komputerami tworzy prawie cykl. Jednocześnie mając do dyspozycji bardzo rozbudowaną strukturę okablowania tworzącą graf.

Praktyczne zastosowanie cyklu Eulera.

Cykl ten może mieć zastosowanie wszędzie tam, gdzie wymagane jest w grafie odwiedzenie wszystkich krawędzi ale każdą z nich odwiedzamy tylko jeden raz niezależnie od ile razy odwiedzany był każdy wierzchołek

1

10

0x01 graphic

0x01 graphic

0x01 graphic

0x01 graphic

0x01 graphic

0x01 graphic



Wyszukiwarka

Podobne podstrony:
Cykle koniunkturalne[1]
1 Role i Cykle opr
Cykle życia
do metody Eulera
03H Cykle prosteid 4727 Nieznany (2)
cykle robaków, ~FARMACJA, I rok, biologia z genetyką
48 Na czym polega różnica między zmiennymi Lagrangea i zmiennymi Eulera
numerol cykle
globalne cykle biochemiczne wykład 10
parazytologia, cw 2, cykle zyci Nieznany
Introduction to Lagrangian and Hamiltonian Mechanics BRIZARD, A J
Cykle koniunkturalne i bezrobocie CALOSC
cykl Kolejarz 3, ZHP - przydatne dokumenty, Cykle
CYKLE BIOCHEMICZNE 5 STR , Inne
cykl Krawcowa 1, ZHP - przydatne dokumenty, Cykle
Nasz własny kawałek Nibylandii, Cykle sprawnościowe, Piotruś Pan- konspekty zajęć
Ognisko, Cykle sprawnościowe, Piotruś Pan- konspekty zajęć
cykl Dworka i Bolkowy woj 1, ZHP - przydatne dokumenty, Cykle

więcej podobnych podstron