2012-01-30 11 views
10

pytanie brzmi tak: istnieje posortowana lista n liczb. Biorąc pod uwagę x, znajdź liczbę, która jest równa x na posortowanej liście. Tutaj zakładamy, że x jest rzeczywiście na liście. Istnieje wyrocznia, która może odpowiedzieć "tak" lub "nie" na twoje pytanie "czy x> = y?". W przeciwieństwie do zwykłego wyszukiwania binarnego, wyrocznia może położyć się raz na twoje pytanie. Najbardziej naiwnym sposobem rozwiązania tego problemu jest zadawanie każdemu z pytań dwa razy przed wyrocznią. Jeśli obie odpowiedzi są takie same, wiesz, że orale nie kłamie. Ten algorytm musimy porównać 2log_2 (n) razy. Ale to pytanie wymaga ode mnie znalezienia algorytmu, który może znaleźć x przy użyciu tylko porównań log_2 (n) + o (logn).jak zrobić wyszukiwanie binarne w jednym modelu kłamstwa?

Próbowałem bardzo mocno, ale się nie udało. Czy ktoś może mi doradzić, jak rozwiązać ten problem? Dziękuję Ci.

+4

'2 * log_2 (N)' i 'log_2 (n) + O (log (N))' są oba 'O (log (N))'. Ukrytą stałą można użyć do zmiany bazy logów. Jesteś pewien, że to były kryteria rozwiązania? – phs

+0

ok. Złożoność jest taka sama, czyli O (log (N)). Masz rację. Pytanie to jednak wymaga od mnie znalezienia algorytmu, który kosztowałby tylko porównania log_2 (n) + o (logn). Jest to mniej niż 2 * log_2 (n) porównań w naiwnym wyszukiwaniu binarnym, zadając dwa razy za każdym razem. Przykro mi, że nie wyjaśniam wystarczająco tego pytania. –

+0

Pamiętaj, że musisz trzykrotnie poprosić o wykrycie prawidłowej odpowiedzi, jeśli jedna z odpowiedzi jest nieprawidłowa. – OleGG

Odpowiedz

3

Śledź interwał, w którym jesteś. Jeśli potrzebujesz łącznie k pytań, sprawdź spójność (niezależnie od tego, czy masz być w przedziale, jaki powinien być) co krok sqrt(k). Podczas sprawdzania spójności możesz zadać każdemu pytanie dwa razy, aby mieć pewność. Jeśli wykryjesz niespójność, cofnij się o kolejne kroki. Będziesz zadawać nie więcej niż c*sqrt(k) dodatkowych pytań.

+0

Myślę, że podajesz ogólną metodę rozwiązania tego problemu. sqrt (k) to tylko jeden z możliwych sposobów. Może być log (k) może również pomóc. Istotnym punktem jest to, że musisz ponownie sprawdzić kroki (o) k). Następnie algorytm w końcu dałby ci złożoność k + o (k). –

+0

hehe, myślę, że n.m oznacza k pytań, a nie długość posortowanej listy.Tutaj potrzebujemy logn pytania więc k = O (logn). –

+0

@ hhn007: dokładnie k pytań. Dlaczego sqrt (k)? Ponieważ jeśli sprawdzisz co t kroków, możesz zapytać o t lub o k/t dodatkowe pytania, w zależności od tego, czy wyrocznia znajduje się blisko początku, czy blisko końca. Aby zagwarantować, że zarówno t, jak i k/t są małe, musisz je wyrównać. –

1

Tylko zapytaj wyrocznię: "czy x> = y?" raz na każdej iteracji twojego binarnego wyszukiwania. Jeśli otrzymasz tę samą odpowiedź dwa razy, to wiesz, że wyrocznia nie kłamała za pierwszym razem.

Na przykład, wyszukujesz x = 1, a pierwszy test testujesz przeciwko y = a, a oracle odpowiada x <. W drugim teście przetestuj przeciwko y = b, a oracle odpowiada x < b. Ponieważ używasz wyszukiwania binarnego, a wyrocznia mówi "<", a tablica jest posortowana, wiesz, że b < a. Dlatego, jeśli x < b, wiesz również, że x < a, a pierwsza odpowiedź nie była kłamstwem. Jeśli druga odpowiedź jest kłamstwem, a x> b, to nadal jest prawdą, że x < a, ponieważ wyrocznia może leżeć tylko raz.

Dzieje się tak, nawet jeśli odpowiedzi nie powrócą. Na przykład otrzymujesz trzy odpowiedzi: x < a, x> = b, x < c, wiesz, że c < a, przez twoje wyszukiwanie binarne, i tak musiało być prawdą, że x < a, a wyrocznia nie była leżąc, kiedy ci to powiedział.

Co się dzieje, gdy wyrocznia mówi kłamstwo? Jeśli kłamstwo było x < y, wtedy prawda była x> = y. Dlatego, gdy będziesz kontynuował wyszukiwanie binarne, od tego momentu sprawdzane liczby będą zbyt małe, a odpowiedź zawsze będzie "> =", aż dojdziesz do końca wyszukiwania binarnego. W tym momencie zdajesz sobie sprawę, że jeśli wyrocznia kłamała, kłamał, gdy ostatnio powiedział ci coś innego niż "> =". Więc ponownie uruchomiłeś wyszukiwanie binarne w punkcie, w którym wyrocznia cię okłamała i powiedziałeś "x < y".

To zawsze użyje < 2 log_2 n porównań, ale jeśli wyrocznia leży ci na początku wyszukiwania, będziesz musiał powtórzyć prawie log_2 n pracy, a więc nie dostaniesz log_2 n + o (log n) odpowiedź, której szukałeś. Tak więc powinieneś włączyć ideę sugerowaną przez nm. Jeśli otrzymasz taką samą odpowiedź, powiedzmy sqrt (log n) razy z rzędu, wtedy podejrzewasz, że wyrocznia mogła cię okłamać, i natychmiast ponownie zadajesz pytanie, które zapytał tuż przed tym, jak odpowiedzi zaczęły się powtarzać, zamiast czekać aż do końca wyszukiwania binarnego. Zgodnie z tą strategią, w najgorszym przypadku będziesz ponownie pytał o log n/sqrt (log n) razy, i zawsze będziesz łapał kłamstwo co najwyżej sqrt (log n) marnowanej pracy, która osiąga czas pracy szukam.

+0

dziękuję. Pomagasz mi lepiej zrozumieć całe pytanie. To ciekawe pytanie, prawda? –

+0

Tak, to jest interesujące. Odpowiedź n.m. z pewnością jest poprawna, ale pomyślałem, że trochę więcej szczegółów wskaże intuicję. Musisz tylko dokładnie sprawdzić odpowiedź oracle, jeśli się powtarza. – Joe

+0

+ 1 miłe intuicyjne myślenie – cctan

0

Możesz zmienić klasyczną przeszukiwanie binarne dla tej pracy, jak o próbie zapytać wyrocznię w każdej iteracji, aby porównać 2 indeksy rozróżnianie tablicy zamiast tylko 1, coś jak:

assume Oracle(x,y) returns "x>=y?", assume every division is returning floor integer. 
LyingOracleSearch(A,n,toFind) 
1. if (n==0) return not found 
2. if (A[0]==toFind) return found 
3. if (Oracle(A[n/4],toFind) and Oracle(toFind,A[3n/4]) then 
4.      return LyingOracleSearch(A[(n/4)...(3n/4)],3n/4-n/4,toFind) 
5. if (Oracle(A[n/4],toFind) and !Oracle(toFind,A[3n/4]) then 
6.      return LyingOracleSearch(A[0...(n/4)],n/4,toFind) 
7. if (!Oracle(A[n/4],toFind) and Oracle(toFind,A[3n/4]) then 
8.      return LyingOracleSearch(A[(3n/4)...n],n-3n/4,toFind) 
9. return LyingOracleSearch(A,n,toFind); \\orcale lied! 

Myślę, że to nails, może być źle.

jego złożoność jest taka sama, jak w oryginalnym BS, ale lepiej jest poprosić oracle dwa razy lub więcej. Zauważ, że element nigdy nie jest porównywany z dwukrotnością, chyba że wyrocznia leży, więc jeśli kłamie raz lub nawet k razy gdzie k jest małe-o (logn), to jesteśmy w porządku.

możesz przejść do swojego ulubionego środowiska kodowania i spróbować go zakodować, za każdym razem, gdy dokonasz porównania, policz to. spróbuj zarówno tego, jak i naiwnego, i porównaj wynik, jeśli się nie mylę, naiwność powinna porównać dwa razy więcej.

Zauważ, że nie byłem zbyt ostrożny z indeksami, musisz się trochę zastanowić, aby upewnić się, że nie straciłem indeksu lub że nie powtarzałam się przypadkowo.

+0

Niezły pomysł. Czy możesz jednak zapewnić, że Twój algorytm jest lepszy niż naiwne wyszukiwanie binarne (za każdym razem pytaj dwa razy)? Próbowałem też na wiele sposobów podzielić listę i skonstruować trzy indeksy: "wyrocznia mówi, że x jest w środku", druga "wyrocznia mówi, że x jest poza nią raz", trzecia "wyrocznia mówi, że x jest poza nim dwa razy ". Wtedy mogę wyrzucić elementy w trzecim. Jednak ten algorytm wydaje się działać po pierwszym kroku. –

+0

edytowane, sprawdź, czy je otrzymasz. –

+0

ok, spróbuję tego. Dzięki i tak. –

2

Skorzystaj z faktu, że po tym, jak wyrocznia kłamie, wyszukiwanie binarne przebiega nieprawidłowo, a od tego czasu nie otrzymujesz żadnej zmiany w odpowiedzi oracle (zawsze >= lub zawsze <). Jeśli nie otrzymasz żadnych zmian w odpowiedzi na pytanie o krok log(log(n)), sprawdź spójność interwałów. Jeśli bieżący interwał jest niespójny, zapytaj wyrocznię jeszcze raz, a jeśli nadal jest niespójna, cofnij się o log(log(n)) + 1 kroków i kontynuuj normalne wyszukiwanie binarne.

Ta procedura wymaga sprawdzania zgodności średnio i do log(log(n)) dodatkowych kroków wyszukiwania binarnego.

Średnia liczba dodatkowych pytań to c*log(log(n)), maksymalna liczba dodatkowych pytań to log(n)/(log(log(n))) + log(log(n)).

+0

dobra. Myślę, że masz rację. Zauważam też, że kiedy wyrocznia mówi ci kłamstwo, po tym zawsze da ci to ten sam kierunek. Sprytnie jest sprawdzić spójność po log (log (n)) krokach. Ale dlaczego dodajesz 2 przed logiem (log (n))? dlaczego nie tylko logować (log (n))? Ponieważ istnieje co najwyżej log (n)/log (log (n)) razy, aby sprawdzić ponownie. Być może masz na myśli log (n)/log (log (n)) + log (log (n)) jako maksymalną liczbę dodatkowych pytań? –

+0

Dobrze, będzie działać z 'log (log (n))'. –

1

Myślę, że rozwiązanie tego pytania w 3 * log(n) może być łatwe, zadając pytanie o nierówność trzy razy na każdym kroku, a decyzja jest najważniejsza.

Powiązane problemy