Jak udowodnić, że chciwy algorytm jest poprawny


29

Mam chciwy algorytm, który, jak podejrzewam, może być poprawny, ale nie jestem pewien. Jak sprawdzić, czy jest poprawny? Jakich technik należy użyć do udowodnienia, że ​​chciwy algorytm jest poprawny? Czy istnieją wspólne wzorce lub techniki?

Mam nadzieję, że stanie się to pytaniem referencyjnym, które można wykorzystać do wskazania początkującym; stąd jego szerszy niż zwykle zakres. Prosimy o podanie ogólnych, dydaktycznie przedstawionych odpowiedzi, które są zilustrowane co najmniej jednym przykładem, ale mimo to obejmują wiele sytuacji. Dzięki!



Czy możemy udowodnić, że chciwy algorytm jest poprawny, używając matroidu lub chciwości?
zdm

Odpowiedzi:


24

Ostatecznie będziesz potrzebować matematycznego dowodu poprawności. Poniżej przedstawię kilka technik dowodowych, ale najpierw, zanim się do nich zagłębię, pozwól mi zaoszczędzić trochę czasu: zanim zaczniesz szukać dowodu, wypróbuj losowe testy.

Losowe testy

Jako pierwszy krok zalecamy przetestowanie algorytmu przy użyciu losowych testów. To zadziwiające, jak skuteczne jest to: z mojego doświadczenia wynika, że ​​w przypadku chciwych algorytmów losowe testowanie wydaje się nieuzasadnione. Poświęć 5 minut na kodowanie algorytmu, a możesz zaoszczędzić godzinę lub dwie, próbując znaleźć dowód.

Podstawowa idea jest prosta: zaimplementuj swój algorytm. Zaimplementuj również algorytm referencyjny, o którym wiesz, że jest poprawny (np. Taki, który wyczerpująco wypróbowuje wszystkie możliwości i bierze najlepsze). W porządku, jeśli algorytm referencyjny jest asymptotycznie nieefektywny, ponieważ uruchamiasz go tylko w przypadku małych problemów. Następnie losowo wygeneruj milion małych wystąpień problemów, uruchom oba algorytmy na każdym z nich i sprawdź, czy algorytm kandydujący daje poprawną odpowiedź w każdym przypadku.

Empirycznie, jeśli twój kandydat na chciwy algorytm jest niepoprawny, zazwyczaj odkryjesz go podczas losowych testów. Jeśli wydaje się być poprawny we wszystkich przypadkach testowych, należy przejść do następnego kroku: wymyślenie matematycznego dowodu poprawności.

Matematyczne dowody poprawności

OK, więc musimy udowodnić, że nasz chciwy algorytm jest poprawny: że generuje optymalne rozwiązanie (lub, jeśli istnieje wiele optymalnych rozwiązań, które są równie dobre, że wypisuje jedno z nich).

Podstawowa zasada jest intuicyjna:

Zasada: jeśli nigdy nie dokonasz złego wyboru, zrobisz dobrze.

Chciwe algorytmy zwykle obejmują sekwencję wyborów. Podstawowa strategia dowodowa polega na tym, że spróbujemy udowodnić, że algorytm nigdy nie dokonuje złego wyboru. Chciwe algorytmy nie mogą cofnąć się - gdy dokonają wyboru, są zobowiązane i nigdy nie cofną tego wyboru - dlatego ważne jest, aby nigdy nie dokonali złego wyboru.

Co by się liczyło jako dobry wybór? Jeśli istnieje jedno optymalne rozwiązanie, łatwo jest zobaczyć, co jest dobrym wyborem: każdy wybór identyczny z wyborem optymalnym. Innymi słowy, postaramy się udowodnić, że na dowolnym etapie wykonywania zachłannych algorytmów sekwencja wyborów dokonanych przez algorytm dokładnie odpowiada pewnemu przedrostkowi optymalnego rozwiązania. Jeśli istnieje wiele równie dobrych optymalnych rozwiązań, dobrym wyborem jest takie, które jest zgodne z co najmniej jednym z optymów. Innymi słowy, jeśli sekwencja wyborów algorytmu do tej pory odpowiada przedrostkowi jednego z optymalnych rozwiązań, na razie wszystko jest w porządku (jak dotąd nic się nie stało).

Aby uprościć życie i wyeliminować zakłócenia, skupmy się na przypadku, w którym nie ma żadnych powiązań: istnieje jedno, unikalne, optymalne rozwiązanie. Wszystkie maszyny zostaną przeniesione do skrzyni, w której może istnieć wiele równie dobrych optymów bez żadnych zasadniczych zmian, ale trzeba być bardziej ostrożnym w kwestii szczegółów technicznych. Zacznij od zignorowania tych szczegółów i skupienia się na przypadku, w którym optymalne rozwiązanie jest unikalne; które pomogą Ci skupić się na tym, co najważniejsze.

Istnieje bardzo popularny wzór dowodu, którego używamy. Będziemy ciężko pracować, aby udowodnić następującą właściwość algorytmu:

Twierdzenie: Niech będzie wyjściem algorytmu, a O rozwiązaniem optymalnym. Jeśli S różni się od O , to możemy dostosować O dostać innego rozwiązania O * , który różni się od O i ściśle lepiej niż O .SOSOOOOO

Zauważ, dlaczego jest to przydatne. Jeśli twierdzenie jest prawdziwe, oznacza to, że algorytm jest poprawny. Jest to w zasadzie dowód sprzeczności. Albo jest taki sam jak O lub jest inny. Jeśli jest inaczej, możemy znaleźć inne rozwiązanie O ∗, które jest zdecydowanie lepsze niż O - ale to sprzeczność, ponieważ zdefiniowaliśmy O jako rozwiązanie optymalne i nie może być żadnego rozwiązania, które byłoby lepsze od tego. Jesteśmy więc zmuszeni stwierdzić, że S nie może różnić się od O ; S musi zawsze być równe OSOOOOSOSO, tj. chciwy algorytm zawsze wyświetla poprawne rozwiązanie. Jeśli możemy udowodnić powyższe twierdzenie, udowodniliśmy, że nasz algorytm jest poprawny.

W porządku. Jak więc udowodnimy roszczenie? Myślimy o rozwiązaniu jako wektorze ( S 1 , , S n ), który odpowiada sekwencji n wyborów dokonanych przez algorytm, i podobnie myślimy o optymalnym rozwiązaniu O jako wektorze ( O 1 , , o n ) odpowiadający sekwencji wyborów, które prowadziłoby do o . Jeśli S różni się od O , musi istnieć jakiś indeks i, gdzie S iS(S1,,Sn)nO(O1,,On)OSOi ; skupimy się na najmniejszym takim ja . Następnie będziemy podkręcać O zmieniając O trochę w I th pozycję na mecz S I , czyli będziemy podkręcać Rozwiązaniem optymalnym O zmieniając I th wybór do jednego, wybranego przez algorytm zachłanny, a następnie pokażemy, że prowadzi to do jeszcze lepszego rozwiązania. W szczególności, będziemy definiować O * za cośSiOiiOOiSiOiO

O=(O1,O2,,Oi1,Si,Oi+1,Oi+2,,On),

z wyjątkiem tego, że często będziemy musieli nieznacznie zmodyfikować część aby zachować globalną spójność. Część strategii dowodowej polega na pewnej sprytności w odpowiednim zdefiniowaniu O . Następnie mięso dowodu będzie w jakiś sposób wykorzystywało fakty na temat algorytmu i problem wykazania, że O jest zdecydowanie lepsze niż OOi+1,Oi+2,,OnOOO; tam potrzebujesz szczegółowych informacji na temat problemu. W pewnym momencie musisz zagłębić się w szczegóły konkretnego problemu. Ale to daje poczucie struktury typowego dowodu poprawności dla chciwego algorytmu.

Prosty przykład: podzbiór z maksymalną sumą

Może to być łatwiejsze do zrozumienia, szczegółowo omawiając prosty przykład. Rozważmy następujący problem:

Wejście: zbiór liczb całkowitych, liczba całkowita k Wyjście: zbiór S U wielkości k, którego suma jest tak duża, jak to możliweUk
SUk

Istnieje naturalny algorytm zachłanny dla tego problemu:

  1. Ustaw .S:=
  2. Dla : i:=1,2,,k
    • Niech być największa liczba w U , które nie zostały jeszcze pobrane (czyli ja th największa liczba w U ). Dodatek x I do S .xiUiUxiS

Losowe testy sugerują, że zawsze daje to optymalne rozwiązanie, więc formalnie udowodnijmy, że ten algorytm jest poprawny. Pamiętaj, że optymalne rozwiązanie jest wyjątkowe, więc nie będziemy musieli martwić się o więzi. Udowodnijmy roszczenie przedstawione powyżej:

Twierdzenie: Niech będzie wyjściem rozwiązania przez ten algorytm na wejściach U , k i O rozwiązaniem optymalnym. Jeśli S O , można skonstruować inne rozwiązanie O * , których suma jest nawet większy niż O .SU,kOSOOO

Dowód. Załóżmy, i pozwolić i jest indeksem pierwszej iteracji, gdzie x iO . (Taki indeks i musi istnieć, ponieważ przyjęliśmy S O, a według definicji algorytmu mamy S = { x 1 , , x k } .) Ponieważ (z założenia) i jest minimalne, musimy mieć x 1 , , x i - 1O , w szczególności,SOixiOiSOS={x1,,xk}ix1,,xi1O ma postać O = { x 1 , x 2 , , x i - 1 , x i , x i + 1 , , x n } , gdzie liczby x 1 , , x i - 1 , x i , , x nOO={x1,x2,,xi1,xi,xi+1,,xn}x1,,xi1,xi,,xnsą wymienione w kolejności malejącej. Patrząc na to, jak algorytm wybiera , widzimy, że musimy mieć x i > x j dla wszystkich j i . W szczególności x i > x i . Zdefiniuj więc O = O { x i } { x i } , tzn. Otrzymamy O poprzez usunięcie i- tej liczby w Ox1,,xixi>xjjixi>xiO=O{xi}{xi}OiOi dodając . Teraz suma elementów O * jest sumą elementów O Plus x I - x ' I , a x I - x ' I > 0 , więc wy * 's suma jest większa niż ściśle O ' sumy s. To potwierdza roszczenie. xiOOxixixixi>0OO

Intuicja polega na tym, że jeśli chciwy algorytm dokona wyboru niezgodnego z , to możemy udowodnić, że O mógłby być jeszcze lepszy, gdyby został zmodyfikowany w celu włączenia elementu wybranego przez chciwy algorytm na tym etapie. Ponieważ O jest optymalne, nie może być żadnego sposobu, aby uczynić go jeszcze lepszym (byłoby to sprzecznością), więc jedyną pozostałą możliwością jest to, że nasze założenie było błędne: innymi słowy, zachłanny algorytm nigdy nie dokona wyboru które są niezgodne z o .OOOO

Ten argument jest często nazywany argumentem wymiany lub lematem wymiany . Znaleźliśmy pierwsze miejsce, w którym optymalne rozwiązanie różni się od chciwego rozwiązania i wyobrażaliśmy sobie, że wymienimy ten element na odpowiadający mu chciwy wybór (zamieniliśmy x i na x i ). Niektóre analizy wykazały, że ta wymiana może jedynie poprawić optymalne rozwiązanie - ale z definicji optymalne rozwiązanie nie może zostać ulepszone. Jedyny wniosek jest taki, że nie może być miejsca, w którym optymalne rozwiązanie różni się od chciwego rozwiązania. Jeśli masz inny problem, poszukaj możliwości zastosowania tej zasady wymiany w konkretnej sytuacji.Oxixi


To stare pytanie, ale dla mnie to pierwszy wynik w Google. Linia then we can tweak O to get another solution O∗ that is different from O and strictly better than Omnie myli. Jeśli istnieje wiele optymalnych rozwiązań, możliwe jest posiadanie S != Oi oba są optymalne; możemy dostosować O, aby było „bardziej podobne” do S (tworząc O ∗), a jednocześnie być tak dobre, jak (nie strictly better than) O.
citelao

@ Citelao, przykro mi słyszeć, że cię to zamieszało. Niestety, nie jestem pewien, jak wyjaśnić to jaśniej. Tak, może istnieć wiele optymalnych rozwiązań, wszystkie o tej samej wartości. To jest poprawne. To, co napisałeś i co napisałem, jest ważne; nie ma sprzeczności. Różnica polega na tym, że to, co napisałeś, nie pomaga udowodnić, że chciwy algorytm jest poprawny; robi to, co napisałem Mogę tylko zasugerować przejrzenie tego, co napisałem ponownie, i sprawdzić, czy możesz dowiedzieć się, jak to, co napisałem, jest przydatne. Jeśli to nie pomoże, może znajdź inny napis. Zdaję sobie sprawę, że to trudne i mylące.
DW

1
Dziękuję za szybką odpowiedź! Brakowało mi punktu, w którym skupiasz się na sprawdzeniu algorytmu, jeśli jest tylko a single, unique optimal solution. Ponieważ pytanie dotyczy udowodnienia poprawności dowolnego chciwego algorytmu, chciałbym udzielić odpowiedzi w przypadkach, w których może istnieć wiele optymalnych rozwiązań. Minęło trochę czasu, odkąd to wszystko przestudiowałem, ale czy to nie wystarczy, aby udowodnić, że możesz wymienić każdy element O_i w dowolnym optymalnym rozwiązaniu O, które różni się od alg. rozwiązanie S z S_i i wciąż ma rozwiązanie O ', które nie jest gorsze niż O?
citelao

@ Citelao, technika ta dotyczy również przypadków, w których istnieje wiele optymalnych rozwiązań. Zasugerowałem skupienie się na przypadku, w którym optymalne rozwiązanie jest wyjątkowe tylko dlatego, że kiedy po raz pierwszy to zobaczysz, łatwiej jest zrozumieć, jak działają te dowody w tym otoczeniu. Ale ta sama strategia działa, nawet jeśli istnieje wiele optymalnych rozwiązań. Sugeruję przestudiowanie tego, upewnienie się, że rozumiesz, jak to działa, gdy istnieje jedno optymalne rozwiązanie, a następnie zastosowanie go do ogólnego przypadku. Myślę też, że może ci pomóc przestudiować kilka przykładowych dowodów na zachłanne algorytmy.
DW

Aby odpowiedzieć na twoje ostatnie pytanie, nie, to nie wystarczy. To nie dowodzi, że S jest optymalny. (Jeśli zażądasz tylko, aby O 'nie było gorsze od O, są przypadki, w których S jest nieoptymalne, ale możliwe jest przeprowadzenie tego rodzaju wymiany. Udowadniając, że możliwe jest osiągnięcie O', które nie jest gorsze niż O nie nie dowodzi niczego, czy S jest optymalny i nie dowodzi, że zachłanny algorytm jest poprawny. Sugeruję przestudiowanie metody opisanej w odpowiedzi nieco bardziej. Jest trudna. Dowód sprzeczności jest często trudny do zrozumienia.)
DW

14

Jako przykład użyję następującego prostego algorytmu sortowania:

repeat:
  if there are adjacent items in the wrong order:
     pick one such pair and swap
  else
     break

Aby udowodnić poprawność, wykonuję dwa kroki.

  • Najpierw pokazuję, że algorytm zawsze się kończy.
  • Następnie pokazuję, że rozwiązanie, w którym się kończy, jest tym, którego chcę.

Po pierwsze, wybieram odpowiednią funkcję kosztu, dla której mogę pokazać, że algorytm poprawia ją na każdym etapie.

AA[i]A[j]A[i]>A[j]i<j

A[i]A[i+1]A[i],A[i+1]

Dowodzi to, że algorytm ostatecznie się kończy.

Liczba inwersji na posortowanej liście wynosi 0. Jeśli wszystko pójdzie dobrze, algorytm zmniejszy liczbę inwersji do 0. Musimy tylko pokazać, że nie utknie w lokalnym minimum.

Zazwyczaj dowodzę tego przez sprzeczność. Zakładam, że algorytm zatrzymał się, ale rozwiązanie jest nieprawidłowe. W tym przykładzie oznacza to, że lista nie jest jeszcze posortowana, ale nie ma sąsiadujących elementów w niewłaściwej kolejności.

A[i]A[j]i<jA[i]>A[j]iji+1<jA[i]<A[i+1]A[i+1]<A[j]A[i]<A[j]

Dowodzi to, że algorytm zatrzymuje się tylko podczas sortowania listy. I tak skończyliśmy.


Wyjaśnione techniki są tak ogólne, że praktycznie nie mają nic szczególnego na temat chciwego algorytmu, będącego tematem tego pytania.
Apass.Jack
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.