Password suspects
03.08.2009 - Alan Meller
![]() ![]() Jednym z moich ulubionych zadań algorytmicznych jest Password Suspects z ACM World Finals 2008. Kapitan naszej drużyny przydzielił mi je wtedy mówiąc, że „to chyba jest dość proste”. Po dokładnym przeczytaniu treści tego oraz innych zadań, które miałem rozwiązać tamtego dnia uznałem, że to jednak nie jest zupełnie trywialne i póki co zajmę się innym, prostszym. Niestety, początek tego konkursu był dla nas nieudany i po około półtorej godziny zaczęliśmy być już mocno z tyłu. Jednocześnie stało się jasne, że jest to zadanie z kategorii tych, które trzeba zrobić by móc liczyć na dobry wynik i że jeśli uda nam się rozwiązać je szybko, będziemy mieli szansę nie stracić kontaktu z czołówką. Zapamiętałem to zadanie właśnie z powodu emocji, które towarzyszyły mi przy jego rozwiązywaniu. Poza tym okazało się ono dosyć oryginalne o tyle, że wymagało zastosowania dwóch różnych kategorii algorytmów. Tego typu zadania nie zdarzają się często i prawie zawsze stanowią ciekawe wyzwanie. ZadanieOryginalną treść zadania można znaleźć tutaj, a jej skrócona wersja wyląda tak: Dane jest
Jeśli takich słów jest co najwyżej 42, należy dodatkowo je wszystkie wypisać. Ograniczenia:
Przykładowo, dla Pierwszy pomysłKrótka analiza zadania doprowadziła mnie do kilku wniosków. Po pierwsze, z całą pewnością nie jest to trywialne zadanie, które można rozwiązać w sposób zupełnie brutalny – wszystkich możliwych słów do sprawdzenia jest potencjalnie Wróciłem więc do analizy zadania, a dokładniej przemyślałem warunki narzucone na słowa, które trzeba zliczyć. Dwa pierwsze wyglądały na proste i naturalne, niestety jednak wszystko komplikował warunek trzeci, tj. zawieranie każdego z danych M wzorców jako spójnego podsłowa. Po sprawdzeniu kilku naiwnych podejść okazało się, że nie jest to proste. Chociażby dlatego, że niektóre spośród tych wzorców mogą mieć wspólne fragmenty, czy wręcz się w sobie zawierać. Ponadto, dopuszczalne są również słowa, w których jakiś z wzorców występuje kilka razy. Tak czy inaczej dość szybko zdałem sobie sprawę, że próby prostego zliczania szukanych słów nie mają szansy powodzenia. Na szczęście wtedy przyjrzałem się dokładniej ograniczeniom danych. Czasami naprawdę warto to zrobić!. Cóż, z praktyki wynika, że w tego typu zadaniach jednym z parametrów przy programowaniu dynamicznym jest długość zliczanych słów. Zazwyczaj okazuje się, że mając wyliczone „pewne informacje” dla wszystkich słów o długości Jeden wzorzecMając w pamięci fakt, że muszę uporać się przede wszystkim z warunkiem trzecim (o wzorcach jako podsłowach) zabrałem się w końcu za ten problem. Pomocnicze pytanie, które można zadać sobie w takiej sytuacji to: „A jak można by to rozwiązać, gdyby był tylko jeden wzorzec?”. Dłuższa chwila zastanowienia i ten uproszczony przypadek okazuje się nie być aż tak trudny. Załóżmy, że wiem ile jest słów długości
Przypadek 1) jest prosty. Do każdego słowa zawierającego wzorzec mogę dopisać na końcu dowolną literę i dalej będzie ono zawierać ten wzorzec. Ponieważ jest tylko Nieco trudniejszy jest przypadek 0). Załóżmy, że mamy słowo, które nie zawiera wzorca, ale jego ostatnich Całe rozumowanie ilustruje następujący (pseudo)kod:
W liniach (1)-(3) zeruję tablicę do której będę dodawał znalezione słowa długości Wracamy do oryginalnej wersjiUmiem więc już rozwiązać prostszą wersję zadania, taką, gdzie jest tylko jeden wzorzec. Spróbuję więc uogólnić to rozumowanie tak, by było ono w stanie obsłużyć nie jeden, lecz
Punkt a) okazuje się być dość prosty. To, które wzorce wystąpiły w tekście, można pamiętać w masce bitowej, tj. w liczbie składającej się z Punkt b) jest trochę bardziej skomplikowany. Idealnym rozwiązaniem jest użycie w tym celu automatu Aho – Corasick. Automat ten jest w pewnym sensie uogólnieniem tablicy prefiksowej użytej w prostszym wariancie zadania, czyli właśnie tym, czego mi potrzeba. Mając zbudowaną tą strukturę dla podanych wzorców, można w algorytmie dynamicznym zamiast ilości ostatnich liter słowa zgodnych z wzorcem pamiętać numer stanu automatu. Wyznaczenie stanu po dodaniu litery jest jeszcze prostsze niż dla tablicy prefiksowej, gdyż wystarczy skorzystać z funkcji przejścia automatu. Ogólnie rozwiązanie korzystające z automatu Aho – Corasick jest w tym zadaniu bardzo eleganckie i zdecydowanie je polecam. Niestety jednak, szczegóły tej struktury wykraczają poza zakres artykułu. Chętni na pewno znajdą wystarczająco dużo materiałów na ten temat w internecie. Niemniej jednak można uporać się z punktem b) również w mniej elegancki sposób. Można na przykład pamiętać ilość liter zgodnych z ostatnimi literami słowa dla każdego wzorca z osobna. Wszystkich możliwości jest co prawda za dużo by pamiętać to w zupełnie brutalny sposób (nawet Koniec?Niestety, historia tego zadania nie ma szczęśliwego zakończenia. Pomimo usilnych starań nie udało się nam rozwiązać go w trakcie trwania zawodów. Nie zmienia to jednak faktu, że zadanie to szczególnie podoba mi się za to, że w interesujący sposób łączy w sobie programowanie dynamiczne z zaawansowanym algorytmem tekstowym. Uważam je również za okazję do ciekawej rozrywki i do nauczenia się czegoś nowego – i przede wszystkim tego życzę wszystkim Czytelnikom :) (2 ocen) |
Copyright © 2008-2010 Wrocławski Portal Informatyczny
design: rafalpolito.com