Przeczytaj
Generowanie wszystkich podzbiorów
Zacznijmy od algorytmu, który jest podstawą w implementacji metod siłowychmetod siłowych do rozwiązywania problemów NP‑zupełnych. Zanim jednak przejdziemy do jego opisu, wprowadźmy pewnego rodzaju oznaczenie. Chcemy, aby ciąg binarny składający się z zer i jedynek reprezentował, które elementy z rozpatrywanego zbioru znajdują się w danym podzbiorze. Niech jedynki i zera oznaczają odpowiednio, że element na danej pozycji znajduje się bądź nie w rozpatrywanym podzbiorze.
Dla lepszego zrozumienia tej koncepcji przeanalizujmy, jak wyglądają reprezentacje przykładowych podzbiorów zbioru .
Reprezentacja w postaci ciągu binarnego | Podzbiór |
---|---|
Dzięki zastosowaniu takiego oznaczenia nie musimy pisać algorytmu generującego faktyczne podzbiory. Potrzebujemy jedynie programu, który wygeneruje nam wszystkie możliwe ciągi binarne, które je reprezentują. Jest to dosyć spore ułatwienie.
Załóżmy, że chcemy wyznaczyć wszystkie podzbiory zbioru n‑elementowego. Każdy z ciągów reprezentujących pewien podzbiór to tak naprawdę zapis binarny liczby naturalnej z zakresu ; przy pomocy n bitów. Wystarczy więc, aby nasz program przeiterował po każdej liczbie naturalnej z zakresu i przekonwertował jej zapis dziesiętny na binarny przy użyciu n bitów.
Jaką złożoność ma przedstawione rozwiązanie? Załóżmy, że przekonwertowanie z zapisu dziesiętnego na binarny wymaga wykonania k operacji. Będziemy wypisywać wszystkie liczby naturalne z zakresu , których w sumie jest . W takim razie algorytm wykona operacji, a więc ma on złożoność czasową .
Warto zastanowić się, dla jakich n nasz algorytm działa w miarę szybko. Dla będzie on działał około minut, natomiast dla czas potrzebny na wykonanie programu wzrasta już do dni. Dlatego właśnie algorytmy o złożoności wykładniczej to ostateczność.
Przykład zastosowania
Co tak naprawdę daje nam znajomość opisanego sposobu generowania podzbiorów? Okazuje się, że jest to bardzo dobry sposób na generowanie wszystkich możliwych rozwiązań pewnego problemu. Załóżmy, że mamy do dyspozycji po jednym z odważników o następujących wagach: , , i . Chcemy wiedzieć, na ile sposobów jesteśmy w stanie uzyskać w sumie . Możemy wykorzystać metodę siłową i wygenerować wszelkie możliwe kombinacje odważników, a następnie sprawdzić, które z zestawów dają wagę taką, jaką chcemy.
Problemy NP‑zupełne
Istnieje wiele problemów, dla których obecnie znanym optymalnym rozwiązaniem są algorytmy o złożoności wykładniczej. Bardzo często ich opis nie wskazuje na faktyczną trudność. W trakcie tego e‑materiału przedstawimy dwa z nich, lecz nie będziemy prezentować ich optymalnych rozwiązań, ponieważ mocno wykraczają one poza zakres programowy.
Problem komiwojażera
Problem komiwojażera to znany problem grafowygrafowy. Tytułowy komiwojażerkomiwojażer musi odwiedzić dokładnie n miast. Chce, aby jego trasa była jak najkrótsza oraz żeby kończyła się w tym samym mieście, w którym się zaczyna. Dodatkowo w trakcie swojej trasy nie chce on wchodzić do żadnego z miast więcej niż jeden raz (nie dotyczy to miasta, z którego startuje).
Problem najdłuższej ścieżki
Mając dany graf, chcemy wiedzieć, czy istnieje ścieżka o długości większej niż pewne zadane s. Ścieżkę definiujemy jako ciąg krawędzi, po których podróżujemy. Dodatkowo zabronione jest wykorzystanie tej samej krawędzi więcej niż jeden raz. Długością ścieżki nazywamy sumę długości krawędzi wchodzącej w jej skład.
Podsumowując, algorytmy o wykładniczej złożoności czasowej są bardzo często wykorzystywane do implementacji metod siłowych. Wtedy mogą one polegać na wygenerowaniu wszystkich możliwych rozwiązań, a następnie sprawdzeniu, które z nich są poprawne. Algorytmy te są jednymi z najwolniejszych i nie powinno się ich stosować dla dużych danych wejściowych.
Do implementacji metod siłowych wykorzystuje się również algorytmy o złożoności czasowej .
Słownik
w uproszczeniu jest to struktura wierzchołków połączonych krawędziami; przykładem grafu może być sieć miast i dróg
przedstawiciel firmy podróżujący w celu zdobywania klientów i przyjmowania zamówień na towar
rozwiązanie polegające na sprawdzeniu wszystkich możliwych odpowiedzi