Odległość Hamminga pomiędzy dwa ciągi o równej długości jest numer pozycji, w którym odpowiednie symbole są różne.
Niech P
będzie dwójkowym ciągiem długości n
i T
dwójkowym ciągiem długości 2n-1
. Możemy obliczyć n
odległości Hamminga między podciągami P
każdej n
długości T
w kolejności od lewej do prawej i umieścić je w tablicy (lub liście).
Przykład sekwencji odległości Hamminga
Niech P = 101
i T = 01100
. Sekwencja odległości Hamminga uzyskana z tej pary to 2,2,1
.
Zadanie
Aby zwiększyć, n
zaczynając od n=1
, rozważ wszystkie możliwe pary ciągów binarnych P
o długości n
i T
długości 2n-1
. Istnieją 2**(n+2n-1)
takie pary, a zatem wiele sekwencji odległości Hamminga. Jednak wiele z tych sekwencji będzie identycznych. Zadanie polega na ustaleniu, ile jest odrębnych dla każdego z nich n
.
Twój kod powinien wypisywać jedną liczbę na wartość n
.
Wynik
Twój wynik jest najwyższy, jaki n
Twój kod osiągnie na moim komputerze w ciągu 5 minut. Czas dotyczy całkowitego czasu działania, a nie tylko tego czasu n
.
Kto wygrywa
Osoba z najwyższym wynikiem wygrywa. Jeśli dwie lub więcej osób uzyska ten sam wynik, wygrywa pierwsza odpowiedź.
Przykładowe odpowiedzi
Ponieważ n
od 1
do 8
optymalnych odpowiedzi są 2, 9, 48, 297, 2040, 15425, 125232, 1070553
.
Języki i biblioteki
Możesz użyć dowolnego dostępnego języka i bibliotek, które ci się podobają. Tam, gdzie jest to wykonalne, dobrze byłoby móc uruchomić kod, więc proszę podać pełne wyjaśnienie, jak uruchomić / skompilować kod w systemie Linux, jeśli to w ogóle możliwe.
Moja maszyna Czasy zostaną uruchomione na moim komputerze 64-bitowym. Jest to standardowa instalacja ubuntu z 8 GB pamięci RAM, ośmiordzeniowym procesorem AMD FX-8350 i Radeon HD 4250. Oznacza to również, że muszę mieć możliwość uruchomienia kodu.
Wiodące odpowiedzi
- 11 w C ++ przez feersum. 25 sekund.
- 11 w C ++ autorstwa Andrew Epsteina. 176 sekund.
- 10 w JavaScript autorstwa Neila. 54 sekundy.
- 9 w Haskell autorstwa nich. 4 minuty i 59 sekund.
- 8 w JavaScript autorstwa fəˈnɛtɪk. 10 sekund.
fastest-code
pozostawia więcej miejsca na optymalizacje dzięki optymalizacji zarówno poziomu kodu, jak i dobrego algorytmu. Myślę więc, żefaster-code
to lepsze niżfaster-algorithm
.Odpowiedzi:
C ++ 11 (powinien dostać się do 11 lub 12)
W tej chwili jest to wątek jednowątkowy.
Kompilować:
źródło
feersum.cpp:111:61: warning: shifting a negative signed value is undefined [-Wshift-negative-value] int middle = int(s >> npre * MAX_N_BITS) & ~(~0 << MAX_N_BITS);
Haskell, ocena 9
Kompiluj z
-O3
. Uruchomienie 6-letniego sprzętu na moim 6-letnim laptopie zajmuje 6n=9
minut, więc może na urządzeniu referencyjnym jest to mniej niż 5 minut.źródło
JavaScript, wynik 10
Wyjaśnienie: Obliczanie
n=10
jest trudne, ponieważ istnieje ponad dwa miliardy par i ponad 26 miliardów potencjalnych sekwencji. Aby przyspieszyć, podzieliłem obliczenia na 121 przedziałów. Ponieważ sekwencje są niezmienne w bitowym uzupełnieniu, mogę założyć bez utraty ogólności, że środkowy bitT
to zero. Oznacza to, że mogę określić pierwszy i ostatni element sekwencji niezależnie od górnychn-1
i dolnychn-1
bitówT
. Każdy pojemnik odpowiada innej parze pierwszego i ostatniego elementu; Następnie przeglądam wszystkie możliwe zestawy górnych i dolnych bitów odpowiadających każdemu przedziałowi i obliczam pozostałe elementy sekwencji, w końcu licząc unikalne sekwencje dla każdego przedziału. Pozostaje wtedy suma wszystkich 121 pojemników. Początkowo trwało to 45 godzin, teraz zakończyłem to w niespełna trzy i pół minuty na moim AMD FX-8120. Edycja: Dzięki @ChristianSievers za 50% przyspieszenia. Pełna wydajność:źródło
n
jako parametr. (Przepraszamy za zły wybór nazwy parametru.)n=1
(nie wiem od razu, dlaczego się zawiesza).C ++, wynik
1011To jest tłumaczenie odpowiedzi @ Neila na C ++, z pewną prostą równoległością.
n=9
kończy się za 0,4 sekundy,n=10
za 4,5 sekundy in=11
za około 1 minutę na moim MacBooku Pro 2015. Również dzięki @ChristianSievers. Dzięki jego komentarzom do odpowiedzi @ Neila zauważyłem dodatkowe symetrie. Od oryginalnych 121 wiader (dlan=10
) do 66 wiader przy rozliczaniu odwrócenia, zjechałem do zaledwie 21 wiader.Użyj następującego skryptu, aby wykonać kod:
Dane wyjściowe były następujące: (Format jest
M: result, seconds
)n=12
obliczenie pojedynczego wątku zajęło 42 minuty, co dało wynik 7368225813.źródło
sudo apt-get install libiomp-dev
.__builtin_popcount
.__builtin_popcount
w kontekście constexpr. Mógłbym przejść do naiwnego wdrożenia i nie wpłynęłoby to na czas działania.JavaScript 2,9,48,297,2040,15425,125232,1070553,9530752
Uruchom w konsoli:
Wypróbuj online!
Lub jako fragment kodu stosu:
Pokaż fragment kodu
Kod wstępnie inicjuje tablicę, aby znacznie przyspieszyć dodawanie 1s do tablicy
Kod znajduje wszystkie sekwencje odległości Hamminga i traktuje je jako bazę liczb (wejście + 1), używa ich do umieszczenia 1 w tablicy. W rezultacie generuje to tablicę z n 1s, gdzie n jest liczbą unikalnych sekwencji odległości hamowania. Na koniec liczba 1 jest liczona za pomocą array.reduce (), aby zsumować wszystkie wartości w tablicy.
Ten kod nie będzie mógł zostać uruchomiony dla wprowadzenia wartości 10, ponieważ osiągnie limit pamięci
Ten kod działa w czasie O (2 ^ 2n), ponieważ tyle elementów generuje.
źródło
n = 9
przy użyciu node.js zajmuje mi 5 minut i 30 sekund, więc jest po prostu zbyt wolny.n = 8
początkowo zajmował 24 sekundy na moim komputerze, ale udało mi się zoptymalizować kod, więcn = 8
zajęło mi to 6 sekund. Potem spróbowałemn = 9
i zajęło to 100 sekund.