background image

 

Raport z projektu 

Przedmiot: Algorytmy i złożoność 

PROJEKT: WIEŻE HANOI 

Autor: Kamil Adamuszek 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

background image

1. 

Opis problemu wież Hanoi 

“W wielkiej świątyni Benares w Hanoi, pod kopułą, która zaznacza środek świata, znajduje się płytka z 

brązu, na której umocowane są trzy diamentowe igły, wysokie na łokieć i cienkie jak talia osy. Na jednej z 
tych igieł, w momencie stworzenia świata, Bóg umieścił 64 krążki ze szczerego złota. Największy z nich leży 
na płytce z brązu, a pozostałe jeden na drugim, idąc malejąco od największego do najmniejszego. Jest to 
wieża Brahma. Bez przerwy we dnie i w nocy kapłani przekładają krążki z jednej diamentowej igły na drugą, 
przestrzegając niewzruszonych praw Brahma. Prawa te chcą, aby kapłan na służbie brał tylko jeden krążek 
na raz i aby umieszczał go na jednej z igieł w ten sposób, by nigdy nie znalazł się pod nim krążek mniejszy. 
Wówczas, gdy 64 krążki zostaną przełożone z igły, na której umieścił je Bóg w momencie stworzenia świata, 
na jedną z dwóch pozostałych igieł, wieża, świątynia, bramini rozsypią się w proch i w jednym oka mgnieniu 
nastąpi koniec świata.” 

 

2. 

Rozwiązanie dla 3 krążków

 

Problem dla 3 krążków można rozwiązać za pomocą algorytmu rekurencyjnego lub iteracyjnego.  

Przykład algorytmu rekurencyjnego: 

 

void Hanoi(int k, int s) 

if (k == 0) return; 

Hanoi(k – 1, -s); 

Przenies(k, s); // Przenoszenie k-tego krążka od s pozycji 

Hanoi(k– 1, -s); 

 

Problem ten można rozwiązać za pomocą algorytmu iteracyjnego. Aby tego dokonać należy zauważyć, że 
krążki są przemieszczane za pomocą wzoru: przykładowo k-ty krążek jest przenoszony z 1 słupka co           
2

k

-2

k-1

o y=(-1)

k+1 

, gdzie gdy y= 1 to krążek jest przenoszony na wieżę po swojej prawej stronie, a gdy y= -1 

to krążek jest przenoszony na wieżę po swojej lewej stronie. 

 

int il_przenies = pow(il_do_przel) - 1; 

 

for (int j = 1; j <= il_przenies; j++) 

 

{  //Sprawdzanie który krazek ma byc przesuniety 

 

int k = 0; 

 

while (true) 

 

 

int a = pow(k); 

 

int b = a * 2; 

 

//Korzystajac z numeru przeniesienia obliczane jest ktory krazek ma 

 

//zostać przemieszczony. Wykonywane to jest przy wykorzystaniu  

 

// j-2

k

 % 2

k+1

==0, gdzie a=2

k

, b=2

k+1

 

background image

 

if (((j - a) % b) == 0) 

 

{           //Przesuwanie krazka 

 

kreg[k] += ((k + 1) % 2) ? 2 : 1; 

 

kreg[k] = kreg[k] % 3; 

              il_przel++; 

 

ofstream plik; 

 

plik.open("wynik.txt", ios::app | ios::ate); 

 

plik << "Przeniesienie " << k + 1 << "-tego krazka na " << kreg[k] + 1 << " slupek"  <<endl; 

plik.close(); 

 

break; 

 

k++; 

3. 

Testy dla k krążków i s słupków(wież) 

 

Il. kr. 

3 słup. 

4 słup. 

5 słup. 

6 słup.  7 słup.  8 słup. 

9 słup. 

10 słup.  11 słup. 

12 słup. 

15 

15 

7  

31 

31 

15 

11 

63 

63 

27 

17 

13 

11 

11 

11 

11 

11 

127 

127 

49 

27 

19 

15 

13 

13 

13 

13 

255 

255 

93 

47 

29 

21 

17 

15 

15 

15 

511 

511 

179 

85 

47 

31 

23 

19 

17 

17 

10 

1023 

1023 

351 

159 

83 

49 

33 

25 

21 

19 

11 

2047 

2047 

693 

307 

153 

83 

51 

35 

27 

23 

12 

4095 

4095 

1377 

601 

291 

151 

85 

53 

37 

29 

13 

8191 

8191 

2743 

1187 

565 

285 

151 

87  

55 

39 

14 

16383 

16383 

5475 

2359 

1113  

551 

283 

153 

89 

57 

15 

32767 

32767 

10937 

4701 

2207 

1081 

545 

283 

155 

91 

16 

65535 

65535 

21861 

9383 

4393 

2139 

1067 

543 

285 

157 

17 

131071  131071 

43707 

18747 

8763 

4255 

2109 

1061 

543 

287 

18 

262143  262143 

87399 

37473 

17503 

8485 

4191 

2095 

1059 

545 

 
 

background image

4. 

Wykresy 

 

 

 

 
 

0

50000

100000

150000

200000

250000

300000

1

2

3

4

5

6

7

8

9

10 11 12 13 14 15 16 17 18

Il

o

ść 

p

rz

e

n

ie

si

e

ń

 

Ilość krążków 

3 słupki

4 słupki

5 słupków

6 słupków

0

2000

4000

6000

8000

10000

12000

14000

16000

18000

1

2

3

4

5

6

7

8

9

10 11 12 13 14 15 16 17 18

Il

o

ść 

p

rz

e

n

ie

si

e

ń

 

Ilość krążków 

7 słupków

8 słupków

9 słupków

10 słupków

11 słupków

12 słupków

background image

5. 

Algorytm dla 3 słupków

 

Wieżę Hanoi z k krążkami oznaczamy przez s

. Z wyników testów wynika, że                                      

s

=2

-1; s

2

=2

-1; s

3

=2

3

-1;s

4

=2

4

-1;… Na tej podstawie należy przypuszczam, że s

n

=2

n

-1 dla pewnej liczby 

krążków n. Powyższą zależność można sprawdzić indukcyjnie. Wiemy że s

1

=2

1

-1=1, załóżmy że s

n

=2

n

-1, a 

więc s

n+1

=2*s

n

+1=2*(2

n

-1)+1=2

(n+1)

-1. Pokazałem zatem że złożoność algorytmu wynosi O(2

n

). 

 

6. 

Algorytm dla 4 słupków

 

Pomimo tego, że dla 4 słupków algorytm zachowuje się w inny sposób niż dla 3 słupków to 

złożoność obliczeniowa jest taka sama jak dla 3 słupków. Jest to wynikiem tego, że np. dla n 
krążków pierwszym krokiem jest przeniesienie k-1 krążków na inny słupek metodą dla 3 słupków, a 
następnie k-tego krążka. Krok ten powtarza się do momentu przeniesienie wszystkich krążków. 

 

7. 

Algorytm dla 5 słupków

 

Analizując wyniki dla 5 słupków otrzymuję poniższy wzór rekurencyjny: 
 
 

 

 

 

 

 

 

 

2*n-1    

dla n=1,2,3 

 

 

 

 

s

n

2*s

n-1

-n+2 

dla n=2*k+3 

 

 

 

 

 

2*s

n-1

-n+3 

dla n=2*k+2 

 
 
 
Nieudało mi się uprościć tej funkcji rekurencyjnej, ale można zauważyć złożoność algorytmu dla 5 

słupków. Na przykład: 

 
S

6

=2*(s

5

)-n+3=2*(2*(s

4

)-n+2)-n+3=2*(2*(2*(s

3

)-n+3)-n+2)-n+3=2*(2*(2*(2*3-1)-n+3)-n+2)-n+3= 

=2*(2*(2

2

*3-2-n+3)-n+2)-n+3=2*(2*(2

*3-n+1)-n+2)-n+3=2*(2

3

*3-2*n+2-n+2)-n+3= 

=2*(2

3

*3-3*n-4)-n+3=2

4

*3-6n+8-n+3=3*2

4

-7n+11 

 
Uogólniając wzór i podpierając się notacją asymptotyczną złożoność algorytmu wynosi 

O(3*2

n

)=3*O(2

n

 

8. Wnioski

 

Algorytm dla 3 słupków ma złożoność obliczeniową O(2

n

). Wraz z wzrostem ilości słupków 

wydajność algorytmu wzrasta, a ilość potrzebnych przełożeń maleje. Nie znaleziono dotychczas algorytmu, 
który dokonał by przełożenia wszystkich krążków w minimalnej liczbie ruchów. Akceptowane więc są 
wszystkie rozwiązania, które dadzą wynik nie gorszy od naszego i będą miały nie gorszą złożoność.