Wyzwanie polega na znalezieniu najdłuższego łańcucha angielskich słów, w którym pierwsze 3 znaki następnego słowa pasują do ostatnich 3 znaków ostatniego słowa. Użyjesz wspólnego słownika dostępnego w dystrybucjach Linuksa, który można pobrać tutaj:
https://www.dropbox.com/s/8tyzf94ps37tzp7/words?dl=0
który zawiera 99171 angielskich słów. Jeśli twój lokalny Linux /usr/share/dict/words
to ten sam plik (ma md5sum == cbbcded3dc3b61ad50c4e36f79c37084), możesz tego użyć.
Słowa mogą być użyte tylko raz w odpowiedzi.
EDYCJA: Litery muszą być dokładnie takie same, jak duże / małe litery, apostrofy i akcenty.
Przykład prawidłowej odpowiedzi to:
idea deadpan panoramic micra craftsman mantra traffic fiche
która uzyska 8 punktów.
Odpowiedź z najdłuższym prawidłowym łańcuchem słów zostanie zwycięzcą. W przypadku remisu wygra najwcześniejsza odpowiedź. Twoja odpowiedź powinna zawierać listę znalezionych słów i (oczywiście) program, który napisałeś, aby to zrobić.
źródło
Odpowiedzi:
Java, heurystyka faworyzująca wierzchołek, który wywołuje największy wykres:
1825 18551873Poniższy kod działa w niecałe 10 minut i znajduje następującą ścieżkę:
Podstawowe pomysły
W przybliżeniu najdłuższych kierowanych ścieżek i cykli , Bjorklund, Husfeldt i Khanna, Lecture Notes in Computer Science (2004), 222-233, autorzy sugerują, że na rzadkich wykresach ekspanderów można znaleźć długą ścieżkę poprzez chciwe wyszukiwanie, które wybiera się przy każdym przesuń sąsiada bieżącego ogona ścieżki, który obejmuje największy podgraph w G ', gdzie G' jest oryginalnym wykresem z usuniętymi wierzchołkami w bieżącej ścieżce. Nie jestem pewien, czy jest dobry sposób na sprawdzenie, czy wykres jest wykresem ekspandera, ale z pewnością mamy do czynienia z wykresem rzadkim, a ponieważ jego rdzeń ma około 20000 wierzchołków i ma średnicę tylko 15, musi mieć dobry właściwości ekspansyjne. Przyjmuję więc tę chciwą heurystykę.
Na podstawie wykresu
G(V, E)
możemy ustalić, ile wierzchołków jest osiągalnych z każdego wierzchołka za pomocą Floyd-Warshall wTheta(V^3)
czasie lub za pomocą algorytmu Johnsona wTheta(V^2 lg V + VE)
czasie. Wiem jednak, że mamy do czynienia z wykresem, który ma bardzo duży silnie połączony komponent (SCC), więc podchodzę do innego podejścia. Jeśli zidentyfikujemy SCC za pomocą algorytmu Tarjana, otrzymamy również sortowanie topologiczne skompresowanego wykresuG_c(V_c, E_c)
, który zO(E)
czasem będzie znacznie mniejszy . PonieważG_c
jest to DAG, możemy obliczyć osiągalnośćG_c
naO(V_c^2 + E_c)
czas. (Następnie odkryłem, że jest to wskazane w ćwiczeniu 26-2.8 CLR ).Ponieważ dominującym czynnikiem w czasie wykonywania jest
E
, optymalizuję go, wstawiając atrapy węzłów dla prefiksów / sufiksów. Więc zamiast 151 * 64 = 9664 krawędzie od słów kończących -res słów zaczynając li- mam 151 krawędzie od słów kończących -res do # # res i 64 krawędzi z # # res na słowa zaczynające się na li- .Wreszcie, ponieważ każde wyszukiwanie zajmuje około 4 minut na starym komputerze, staram się łączyć wyniki z poprzednimi długimi ścieżkami. Jest to o wiele szybsze i znalazłem moje najlepsze najlepsze rozwiązanie.
Kod
org/cheddarmonk/math/graph/Graph.java
:org/cheddarmonk/math/graph/MutableGraph.java
:org/cheddarmonk/math/graph/StronglyConnectedComponents.java
:org/cheddarmonk/ppcg/PPCG.java
:źródło
Ruby, 1701
"Del" -> "ersatz's"
( pełna sekwencja )Próba znalezienia optymalnego rozwiązania okazała się zbyt kosztowna w czasie. Dlaczego więc nie wybierać losowych próbek, buforować, co możemy i mieć nadzieję na najlepsze?
Najpierw
Hash
budowane jest a, które odwzorowuje prefiksy na pełne światy, zaczynając od tego prefiksu (np"the" => ["the", "them", "their", ...]
.). Następnie dla każdego słowa na liściesequence
wywoływana jest metoda . Pobiera słowa, które mogą wynikać zHash
, pobiera próbkę100
i nazywa się rekurencyjnie. Najdłużej jest zajęty i dumnie pokazany. Ziarno dla RNG (Random::DEFAULT
) i długość sekwencji.Musiałem uruchomić program kilka razy, aby uzyskać dobry wynik. Ten konkretny wynik został wygenerowany z nasionem
328678850348335483228838046308296635426328678850348335483228838046308296635426
.Scenariusz
źródło
0.0996
sekundy.Wynik:
16311662 słówCałą sekwencję można znaleźć tutaj: http://pastebin.com/TfAvhP9X
Nie mam pełnego kodu źródłowego. Próbowałem różnych podejść. Ale oto kilka fragmentów kodu, które powinny być w stanie wygenerować sekwencję o tej samej długości. Przepraszam, to nie jest bardzo piękne.
Kod (Python):
Najpierw wstępne przetwarzanie danych.
Następnie zdefiniowałem funkcję rekurencyjną (pierwsze wyszukiwanie głębokości).
Oczywiście trwa to zbyt długo. Ale po pewnym czasie znalazła sekwencję z 1090 elementami i zatrzymałem się.
Następną rzeczą do zrobienia jest wyszukiwanie lokalne. Dla każdego z dwóch sąsiadów n1, n2 w sekwencji próbuję znaleźć sekwencję rozpoczynającą się od n1 i kończącą się na n2. Jeśli taka sekwencja istnieje, wstawiam ją.
Oczywiście musiałem ręcznie zatrzymać program.
źródło
PHP,
17421795W tym bałaganie z PHP. Sztuką jest na pewno skasowanie listy do około 20 tysięcy, które są rzeczywiście ważne, i po prostu wyrzucenie reszty. Mój program robi to iteracyjnie (niektóre słowa, które wyrzuca w pierwszej iteracji, oznacza, że inne nie są już ważne) na początku.
Mój kod jest okropny, używa wielu zmiennych globalnych, używa o wiele za dużo pamięci (zachowuje kopię całej tabeli prefiksów dla każdej iteracji) i dosłownie kilka dni zajęło mi wymyślenie moich najlepszych, ale nadal zarządza wygrywać - na razie. Zaczyna się dość szybko, ale z czasem staje się coraz wolniejszy.
Oczywistą poprawą byłoby użycie sierocego słowa na początek i koniec.
W każdym razie, naprawdę nie wiem, dlaczego moja lista pastebin została przeniesiona do komentarza tutaj, wrócił jako link do pastebin, ponieważ teraz umieściłem mój kod.
http://pastebin.com/Mzs0XwjV
źródło
Python:
1702-1704- 1733 słówUżyłem Dict, aby zmapować wszystkie prefiksy na wszystkie słowa, as
Edytuj małe ulepszenie: usuwając wszystkie
useless
słowa na początku, jeśli ich przyrostki nie znajdują się na liście prefiksów (oczywiście byłoby to słowo końcowe)Następnie weź słowo z listy i przejrzyj mapę prefiksów jak węzeł drzewa
Program potrzebuje kilku słów, aby wiedzieć, kiedy zatrzymać, można znaleźć jak
1733
w metodziecheckForNextWord̀
Program potrzebuje ścieżki pliku jako argumentu
Niezbyt pytoniczny, ale próbowałem.
Obliczenie tej sekwencji zajęło mniej niż 2 minuty: pełne wyjście :
źródło
Wynik:
2495001001Oto mój kod:
Edycja: 1001:
http://pastebin.com/yN0eXKZm
Edycja: 500:
źródło
Mathematica
14821655Coś na początek ...
Linki to przedrostki i sufiksy wyrazów przecięcia.
Krawędzie to wszystkie bezpośrednie linki od słowa do słowa:
Znajdź ścieżkę między „popraw” a „zest”.
Wynik (1655 słów)
źródło
Python, 90
Najpierw ręcznie czyszczę listę, usuwając wszystko
kosztuje mnie to co najwyżej 2 punkty, ponieważ te słowa mogą znajdować się tylko na początku lub na końcu łańcucha, ale zmniejsza listę słów o 1/3 i nie mam do czynienia z Unicode.
Następnie tworzę listę wszystkich prefiksów i sufiksów, znajduję nakładkę i odrzucam wszystkie słowa, chyba że zarówno prefiks, jak i sufiks znajdują się w zestawie nakładek. Ponownie, to goli najwyżej 2 punkty w stosunku do mojego maksymalnego możliwego do osiągnięcia wyniku, ale zmniejsza listę słów do jednej trzeciej oryginalnego rozmiaru (spróbuj uruchomić algorytm na krótkiej liście dla możliwego przyspieszenia), a pozostałe słowa są ściśle powiązane (z wyjątkiem niektórych 3 -lety słów, które są powiązane tylko ze sobą). W rzeczywistości prawie każde słowo można uzyskać z dowolnego innego słowa na ścieżce o średnio 4 krawędziach.
Przechowuję liczbę łączy w macierzy przylegania, która upraszcza wszystkie operacje i pozwala mi robić fajne rzeczy, takie jak patrzenie n kroków do przodu lub liczenie cykli ... przynajmniej teoretycznie, ponieważ kwadrat zajmuje około 15 sekund to podczas wyszukiwania. Zamiast tego zaczynam od losowego przedrostka i chodzę losowo, albo wybieram zakończenie równomiernie, faworyzując te, które występują często (jak „-ing”) lub te, które występują rzadziej.
Wszystkie trzy warianty zasysają równomiernie i wytwarzają łańcuchy w zakresie 20-40, ale przynajmniej są szybkie. W końcu muszę dodać rekursję.
Początkowo chciałem spróbować czegoś podobnego do tego, ale ponieważ jest to ukierunkowany wykres z cyklami, żaden ze standardowych algorytmów do sortowania topologicznego, najdłuższej ścieżki, największej ścieżki Eulera lub chińskiego listonosza nie działa bez większych modyfikacji.
I tylko dlatego, że wygląda ładnie, oto obraz macierzy przylegania M, M ^ 2 i M ^ nieskończoności (nieskończoność = 32, potem się nie zmienia) z białymi = niezerowymi wpisami
źródło