Napisz funkcję / podprogram, aby posortować listę liczb całkowitych w stylu Tower of Hanoi .
Otrzymasz stos liczb całkowitych. To jest główny stos.
Dostajesz także dwa kolejne stosy pomocników. Te stosy pomocnicze mają jednak unikalną właściwość: każdy element musi być mniejszy lub mieć taki sam rozmiar jak element pod nim. Główny stos nie ma takich ograniczeń.
Twoim zadaniem jest posortowanie głównego stosu na miejscu, umieszczenie pod nim największych liczb całkowitych. Twoja funkcja / podprogram zwróci (lub równoważny) liczbę ruchów wykonanych podczas sortowania stosu.
Uwaga: musisz posortować główny stos na miejscu , bez sortowania na innym stosie i nazywania go odpowiedzią. Jeśli jednak z jakiegoś powodu nie możesz tego zrobić, możesz symulować stosy zmienne, ale pamiętaj, że jest to rodzaj Wieży Hanoi; są tylko 3 kołki i tylko 1 kołek może być nieuporządkowany.
Twoja funkcja / podprogram może w dowolnym momencie sprawdzić dowolny stos, ale może wykonać ruch tylko poprzez pop-up i push. Pojedynczy ruch to pop z jednego stosu, który jest popychany na inny.
Przetestuj swoją funkcję / podprogram dla każdej permutacji pierwszych 6 liczb naturalnych. Innymi słowy, sprawdź swoją funkcję / podprogram pod kątem {1},{2},...,{6},{1,1},{1,2},...,{1,6},{2,1},...
(powinna to być suma możliwości lub możliwości (dzięki Howard za poprawienie mojej matematyki)). Funkcja / podprogram, który porusza elementy najmniej razy, wygrywa.61+62+...+66
55986
źródło
6**1+6**2+...+6**6=55986
elementy.Odpowiedzi:
Java - optymalne rozwiązanie (1080544 ruchów)
To rozwiązanie buduje najkrótsze drzewo ścieżek od celu i do tyłu, a następnie przechodzi od stanu początkowego do celu. Dużo miejsca na poprawę prędkości, ale nadal rozwiązuje wszystkie 55986 problemów w około minutę.
Zakładając, że algorytm jest poprawnie wdrożony, powinno to być teoretycznie najlepsze rozwiązanie.
źródło
C - 2547172 dla 55986 wejść
Jest tu dużo miejsca na ulepszenia. Dla własnego rozsądku uprościłem to, aby można było sprawdzić tylko górny element każdego stosu. Zniesienie tego narzuconego ograniczenia pozwoliłoby na optymalizacje, takie jak wcześniejsze ustalenie ostatecznego zamówienia i próba zminimalizowania liczby ruchów wymaganych do jego osiągnięcia. Ciekawym przykładem jest to, że moja implementacja ma najgorsze zachowanie, jeśli główny stos jest już posortowany.
Algorytm:
Analiza:
źródło
Python,
39838383912258 przenosi ponad 55986 danych wejściowychTo jest bardzo nieefektywne.
Dodam całkowitą liczbę ruchów po tym, jak PO wyjaśni, czy dotyczą one wszystkich tych przypadków, czy konkretnych innych przypadków.
Wyjaśnienie
Co, komentarze nie są dla ciebie wystarczająco dobre?
Uwaga do OP: Dziękujemy za nie zrobienie tego golfa.
źródło
[2,1,1]
jest sposobem na uzyskanie[2,1,1].index(1)
2, tzn. Zaczynając od wyższej klasy?[2,1,1,3,5].index(1)==2
zamiast1
list.index(data)
zwraca indeks elementudata
wlist
. I nie wiem, indeksdata
tj1
len(list)-(list[::-1].index(1))
Python:
166829315791821,5244,0414508421093195 ruchówGłówną metodą jest
main_to_help_best
przenoszenie wybranych elementów ze stosu głównego na stos pomocniczy. Ma flagę,everything
która określa, czy chcemy przenieść wszystko do określonegodestination
, czy też chcemy zachować tylko największydestination
podczas gdy reszta w drugim pomocniku.Załóżmy, że przechodzimy do
dst
używania pomocnikahelper
, funkcję można z grubsza opisać następująco:helper
rekurencyjniedst
helper
do głównegodst
everything
jest ustawiony, rekurencyjnie przenieś elementy w main dodst
b. W przeciwnym razie rekurencyjnie przenieś elementy w głównym do
helper
Algorytm sortowania głównego (
sort2
w moim kodzie) wywoła następnie zamain_to_help_best
pomocąeverything
set toFalse
, a następnie przeniesie największy element z powrotem do main, a następnie przeniesie wszystko z pomocnika z powrotem do main, utrzymując go posortowane.Więcej objaśnień zawartych w komentarzach w kodzie.
Zasadniczo zastosowałem następujące zasady:
Zasada 3 jest realizowana przez nie liczenie ruchu, jeśli źródłem jest poprzedni cel (tj. Właśnie przenieśliśmy główny do help1, a następnie chcemy przejść z help1 do help2), a ponadto zmniejszamy liczbę ruchów o 1, jeśli przesuwają go z powrotem do pierwotnej pozycji (tj. główny do help1, a następnie help1 do main). Ponadto, jeśli wszystkie poprzednie
n
ruchy przenoszą tę samą liczbę całkowitą, możemy faktycznie zmienić ich kolejnośćn
. Wykorzystujemy to również w celu dalszego zmniejszenia liczby ruchów.Jest to ważne, ponieważ znamy wszystkie elementy na głównym stosie, więc można to interpretować jako widzenie w przyszłości, że cofniemy element z powrotem, nie powinniśmy wykonywać tego ruchu.
Przykładowy przebieg (stosy są wyświetlane od dołu do góry - więc pierwszy element jest na dole):
Widzimy, że najgorszym przypadkiem jest umieszczenie największego elementu na drugim dnie, podczas gdy pozostałe są sortowane. W najgorszym przypadku możemy zobaczyć, że algorytmem jest O (n ^ 2).
Liczba ruchów jest oczywiście minimalna
n=1
in=2
jak widać z wyniku, i uważam, że jest to również minimalna wartość dla większych wartościn
, chociaż nie mogę tego udowodnić.Więcej wyjaśnień znajduje się w kodzie.
źródło
4
. Co to jest przechowywanie drugiego co do wielkości elementu drugiego pomocnika? Co to znaczy?Java -
21290902083142 porusza się po 55986 tablicachLink ideone .
Struktura zapewniająca poprawność algorytmu:
Rzeczywisty algorytm:
Testcase:
źródło
C / C ++ Nie mierzyłem ruchów (kołki: p1, p2, p3) Nie wiem, jak dodać kod C ++, który używa STL (problem z formatowaniem). Utrata części kodu z powodu formatów tagów HTML w kodzie.
Scal dane przenoszenia (n + m) w p2 i p3 do p1.
źródło
hanoi(...)
funkcji. Ponadto masz 2#include
s, które się nie kompilują. Proszę zamieścić pełny kod.