W zeszłym tygodniu pracowaliśmy nad stworzeniem najkrótszego ciągu 1-D przy użyciu 10 000 najlepszych słów w języku angielskim . Teraz spróbujmy tego samego wyzwania w 2D!
Wszystko, co musisz zrobić, to wziąć wszystkie powyższe słowa i umieścić je w możliwie jak najmniejszym prostokącie, umożliwiając nakładanie się. Na przykład, jeśli twoje słowa były ["ape","pen","ab","be","pa"]
, to możliwy prostokąt to:
.b..
apen
Powyższy prostokąt dałby wynik 5.
Zasady:
- Dozwolone jest nakładanie wielu liter na słowo
- Słowa mogą iść w dowolnym z 8 kierunków
- Słowa nie mogą się zawijać
- W pustych lokalizacjach możesz użyć dowolnej postaci
Musisz utworzyć wyszukiwanie słów zawierające te 10 000 najlepszych słów w języku angielskim (według Google). Twój wynik jest równy liczbie znaków w wyszukiwaniu słów (z wyłączeniem nieużywanych znaków). Jeśli istnieje remis lub jeśli przesłanie okaże się optymalne, zgłoszenie, które zostanie opublikowane jako pierwsze, wygrywa.
źródło
Odpowiedzi:
Rust,
3143030081 używanych znakówJest to pewien rodzaj chciwego algorytmu: zaczynamy od pustej siatki i wielokrotnie dodajemy słowo, które można dodać z jak najmniejszą liczbą nowych liter, z przerwanymi więzami przez preferowanie dłuższych słów. Aby to działało szybko, utrzymujemy priorytetową kolejkę umieszczania słów kandydujących (zaimplementowaną jako wektor wektorów deques, z wektorem dla każdej liczby nowych liter, zawierającym deque dla każdej długości słowa). Dla każdego nowo dodanego listu kolejkujemy wszystkie miejsca docelowe kandydatów, które przebiegają przez ten list.
Skompiluj i uruchom z
rustc -O wordsearch.rs; ./wordsearch < google-10000-english.txt
. Na moim laptopie działa to w 70 sekund, przy użyciu 531 MiB RAM.Dane wyjściowe mieszczą się w prostokącie z 248 kolumnami i 253 wierszami.
Kod
źródło
C ++, siatka znaków 27243 (248 x 219, wypełnienie 50,2%)
(Publikuję to jako nową odpowiedź, ponieważ chciałbym zachować granicę 1D, którą pierwotnie opublikowałem jako odniesienie)
To
rażące zerwaniejest mocno zainspirowane odpowiedzią @ AndersKaseorg w głównej strukturze, ale ma kilka drobnych poprawek. Po pierwsze, używam mojego oryginalnego programu do scalania ciągów, aż najlepsze dostępne nakładanie się będzie mieć tylko 3 znaki. Następnie używam metody opisanej przez AndersKaseorg do stopniowego wypełniania siatki 2D za pomocą wygenerowanych ciągów. Ograniczenia też są trochę inne: wciąż próbuje dodawać najmniej znaków za każdym razem, ale więzi są zrywane, preferując najpierw kwadratowe siatki, potem małe siatki, a na końcu dodając najdłuższe słowo.Zachowanie, które wyświetla, polega na naprzemiennym wypełnianiu przestrzeni i szybkim rozszerzaniu siatki (niestety zabrakło słów tuż po etapie szybkiego rozszerzania, więc wokół krawędzi jest dużo pustej przestrzeni). Podejrzewam, że z pewnym dopracowaniem funkcji kosztu, którą można by uzyskać, aby uzyskać więcej niż 50% wypełnienia przestrzeni.
Są tutaj 2 pliki wykonywalne (aby uniknąć konieczności ponownego uruchomienia całego procesu podczas iteracyjnej poprawy algorytmu). Dane wyjściowe jednego można przesyłać bezpośrednio do drugiego:
I wreszcie wynik:
Alternatywny wynik (po naprawieniu kilku błędów w programie, które odchylały pewne kierunki i poprawiał funkcję kosztów, otrzymałem bardziej kompaktowe, ale mniej optymalne rozwiązanie): 29275 znaków, 198 x 195 (wypełnione 75,8%):
Znów nie zrobiłem wiele, aby zoptymalizować te programy, więc zajmuje to trochę czasu. Ale możesz obserwować, jak wypełnia siatkę, co jest dość hipnotyczne.
źródło
C ++, 34191 „siatka” znaków (przy minimalnej interwencji człowieka można łatwo zapisać 6 lub 7)
Powinno to być traktowane bardziej jako ograniczenie dla przypadku 2D, ponieważ odpowiedź jest wciąż ciągiem 1D. To tylko mój kod z poprzedniego wyzwania, ale z nową możliwością odwrócenia dowolnego łańcucha. Daje nam to znacznie więcej możliwości łączenia słów (szczególnie dlatego, że ogranicza najgorszy przypadek nie nakładających się superstrun do 26; po jednej na każdą literę alfabetu).
W przypadku niewielkiej atrakcyjności wizualnej 2D umieszcza w wyniku przełamania linii, jeśli może to zrobić za darmo (tj. Między wyrazami 0-nakładającymi się).
Dość powolny (wciąż bez buforowania). Oto kod:
Wynik: http://pastebin.com/UTe2WMcz (4081 znaków mniej niż poprzednie wyzwanie)
Jest całkiem jasne, że można uzyskać trywialne oszczędności, ustawiając linie
xd
iwv
pionowo, przecinając linię potwora. Następniehhidetautisbneudui
może przecinać się zd
, ilxwwwowaxocnnaesdda
zw
. To oszczędza 4 znaki.nbcllilhn
można zastąpić istniejącyms
zakładkiem (jeśli można go znaleźć), aby zapisać kolejne 2 (lub tylko 1, jeśli takie nakładanie nie istnieje i należy je zamiast tego dodać pionowo). Wreszciemjjrajaytq
można dodać gdzieś pionowo, aby zapisać 1. Oznacza to, że przy minimalnej interwencji człowieka można zapisać 6–7 znaków z wyniku.Chciałbym wprowadzić to do 2D za pomocą następującej metody, ale staram się znaleźć sposób na wdrożenie tego bez tworzenia algorytmu O (n ^ 4), co jest dość niepraktyczne!
źródło
PHP
ten wykonuje pracę termicznie; ale 10000 to prawdopodobnie zbyt wiele słów do rekurencji. Skrypt działa teraz. (nadal
działa 24 godziny później) działa dobrze w małych katalogach, ale w przyszłym tygodniu mogę utworzyć wersję iteracyjną.
$f=array("pen","op","po","ne","pro","aaa","abcd","dcba"); will output
abcdalthough this is not an optimal result (scoring was changed ... I´m working on a generator). One optimal result is this:
otwórzNie jest też bardzo szybki; usuwa tylko podciągi i sortuje resztki według długości,
reszta to brutalna siła: spróbuj dopasować słowa do prostokąta, spróbuj na większym prostokącie, jeśli się nie powiedzie.
btw: Część podciągu potrzebuje 4,5 minuty na mojej maszynie dla dużego katalogu
i skraca ją do 6190 słów; sortowanie na nich zajmuje 11 sekund.
źródło