2012-01-30 14 views
10

la domanda è come questa: esiste un elenco ordinato di n numeri. Dato x, trova un numero che è uguale a x nella lista ordinata. Qui assumiamo che x sia effettivamente nella lista. C'è un oracolo che può rispondere "sì" o "no" alla tua domanda "se x> = y?". A differenza della normale ricerca binaria, l'oracolo può mentire una volta alla tua domanda. Il modo più ingenuo per risolvere questo problema è che poni ogni domanda due volte all'oracolo. Se le due risposte sono le stesse, sai che l'orale non sta mentendo. Questo algoritmo ci serve confrontare 2log_2 (n) volte. Ma questa domanda mi chiede di trovare un algoritmo in grado di trovare x usando solo i confronti log_2 (n) + o (logn).come fare la ricerca binaria in un modello di bugia?

Ho provato molto duramente ma non ci sono riuscito. Qualcuno può darmi qualche consiglio su come risolvere questo problema? Grazie.

+4

'2 * log_2 (N)' e 'log_2 (n) + O (log (N))' sono entrambi 'O (log (N))'. La costante nascosta può essere utilizzata per modificare la base del registro. Sei sicuro che quelli erano i criteri di soluzione? – phs

+0

ok. La complessità è la stessa, che è O (log (N)). Hai ragione. Tuttavia, la domanda mi chiede di trovare un algoritmo che costa solo il confronto log_2 (n) + o (logn). Questo è meno di 2 * log_2 (n) confronti nella ricerca binaria ingenua, chiedendo due volte ogni volta. Mi dispiace di non chiarire abbastanza la questione. –

+0

Si noti che è necessario chiedere tre volte di rilevare la risposta corretta se una delle risposte è bugie. – OleGG

risposta

3

tenere traccia del dell'intervallo ci si trova. Se avete bisogno di un totale di k domande, verificare la presenza di consistenza (se si è nel frattempo si suppone di essere) ogni sqrt(k) passi. Mentre controlli la coerenza puoi chiedere a ciascuna domanda due volte per essere sicuro. Se rilevi un'incoerenza, torna indietro sqrt(k) passaggi. Non dovrai fare più di c*sqrt(k) domande aggiuntive.

+0

Penso che dichiari un metodo generale per risolvere questo tipo di problema. sqrt (k) è solo un modo possibile. Può essere log (k) può anche aiutare. Il punto essenziale è che devi ricontrollare in o (k) passi. Quindi l'algoritmo ti darebbe finalmente la k + o (k) complessità. –

+0

hehe, penso n.m vuol dire k domande, non la lunghezza della lista ordinata. Abbiamo bisogno di domande logn in modo k = O (logn). –

+0

@ hhn007: esattamente, k domande. Perché sqrt (k)? Perché se controlli ogni passo di t, puoi chiedere circa t o circa k/t domande extra, a seconda che l'oracolo si trovi vicino all'inizio o vicino alla fine. Per garantire che t e k/t siano piccoli devi renderli uguali. –

1

Solo chiedere all'oracolo la domanda: "è x> = y?" una volta su ogni iterazione della tua ricerca binaria. Se ottieni la stessa risposta due volte, allora sai che l'oracolo non ha mentito per la prima volta.

Ad esempio, si sta cercando x = 1 e il primo test si prova contro y = a e l'oracolo risponde x < a. Nel secondo test si prova contro y = b e l'oracolo risponde x < b. Poiché stai usando la ricerca binaria e l'oracolo ha detto "<" e l'array è ordinato, sai che b < a. Pertanto, se x < b, sai anche che x < a, e la prima risposta non era una bugia. Se la seconda risposta è una bugia, e x> b, allora è ancora vero che x < a, poiché l'oracolo può mentire solo una volta.

Questo è vero anche se le risposte non tornano indietro. Ad esempio ottieni tre risposte: x < a, x> = b, x < c, sai che c < a, dalla tua ricerca binaria, e quindi deve essere stato vero che x < a, e l'oracolo non era mentire quando te l'ha detto.

Quindi cosa succede quando l'oracolo dice una bugia? Se la menzogna era x < y, allora la verità era x> = y. Pertanto, quando si continua la ricerca binaria, da quel momento in poi, i numeri che si verificano saranno tutti troppo piccoli e la risposta sarà sempre "> =", fino a raggiungere il fondo della ricerca binaria. A quel punto, ti rendi conto che se l'oracolo ha mentito, ha mentito l'ultima volta che ti ha detto qualcosa di diverso da "> =". Quindi riavvii la ricerca binaria nel punto in cui l'oracolo ti ha mentito e ha detto "x < y".

Questo utilizzerà sempre < 2 log_2 n confronti, ma se l'oracolo si trova all'inizio della ricerca, sarà necessario ripetere quasi log_2 n lavoro e quindi non si ottiene log_2 n + o (log n) risposta che stavi cercando. Quindi, dovresti incorporare l'idea suggerita da nm. Se ottieni la stessa risposta, ad esempio sqrt (log n) volte di seguito, allora sospetti che l'oracolo potrebbe aver mentito a te, e ti chiedi immediatamente di porre la domanda chiesto prima che le risposte inizino a ripetersi, invece di aspettare fino alla fine della ricerca binaria. Seguendo questa strategia, nel peggiore dei casi richiederete una domanda di log n/sqrt (log n) volte e troverete sempre la bugia con al massimo lo sqrt (log n) lavoro sprecato, che raggiunge il tempo di esecuzione che siete stati cercando.

+0

grazie. Mi aiuti a capire meglio l'intera questione. È una domanda interessante no? –

+0

Sì, è interessante. La risposta del nm è certamente corretta, ma ho pensato che un po 'più di elaborazione avrebbe mostrato di più l'intuizione. Inoltre, devi solo ricontrollare la risposta dell'oracolo se si è ripetuto. – Joe

+0

+1 bel ragionamento intuitivo – cctan

0

Si consiglia di modificare la classica ricerca binaria per far funzionare tutto questo, come su di provare a chiedere l'oracolo in ogni iterazione per confrontare 2 indici differenti di matrice invece di 1, qualcosa come:

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! 

Penso che unghie, potrebbe essere sbagliato tho.

la sua complessità è la stessa della BS originale, ma è meglio chiedere l'oracolo due o più volte. notate che un elemento non viene mai paragonato al doppio a meno che l'oracolo non si trovi, quindi se giace una volta o anche k volte in cui k è piccolo-o (logn) allora stiamo bene.

si può andare al vostro ambiente di codifica preferito e provare a codificarlo, ogni volta che un confronto fatto, contarlo. prova sia questo che l'ingenuo, e confronta il risultato, se non sbaglio, l'ingenuo dovrebbe confrontare il doppio di questo.

Avviso tho, non ero troppo attento con gli indici, è necessario fare un po 'il pensiero per assicurarsi che io wasnt manca un indice o non era la ripetizione di un indice accidentalmente.

+0

Bella idea comunque. Tuttavia, puoi assicurare che il tuo algoritmo sia migliore della ricerca binaria ingenua (ogni volta chiedi due volte)? Ho anche provato molti modi per dividere la lista e costruire tre indici di uno "l'oracolo dice che x è dentro", il secondo "l'oracolo dice che x è fuori per una volta", il terzo "l'oracolo dice che x è fuori per due volte ". Allora posso buttare via gli elementi nel terzo. Tuttavia, questo algoritmo sembra funzionare dopo il primo passaggio. –

+0

modificato, vedi se capisci. –

+0

ok, ci proverò. Grazie comunque. –

2

Utilizzare il fatto che dopo che l'oracle ha mentito, la ricerca binaria diventa errata e non si ottiene alcuna modifica nella risposta dell'oracolo da quel momento (sempre o sempre <). Se non si ottiene alcuna modifica nella risposta dell'oracolo per i passaggi log(log(n)), verificare la coerenza dell'intervallo. Se l'intervallo corrente è incoerente, chiedere ancora una volta all'oracolo e, se ancora incoerente, tornare indietro ai passi log(log(n)) + 1 e continuare con la normale ricerca binaria.

Questa procedura richiede i controlli di coerenza O(log(log(n))) in media e fino a log(log(n)) passaggi di ricerca binaria aggiuntivi.

Numero medio di domande aggiuntive è c*log(log(n)), il numero massimo di domande aggiuntive è log(n)/(log(log(n))) + log(log(n)).

+0

buono. Penso che tu abbia ragione. Noto anche che quando l'oracolo ti dice una bugia, dopo di ciò ti darebbe sempre la stessa direzione. È intelligente controllare i passaggi di coerenza dopo il log (log (n)). Ma perché aggiungi 2 di fronte al log (log (n))? perché non registrare (log (n))? Perché ci sono al massimo log (n)/log (log (n)) volte a controllare. Può essere inteso log (n)/log (log (n)) + log (log (n)) come numero massimo di domande aggiuntive? –

+0

Bene, funzionerà con 'log (log (n))'. –

1

Credo che risolvere questa domanda in 3 * log(n) può essere semplice, ponendo la domanda di disuguaglianza tre volte ad ogni passaggio e la decisione è la maggioranza.

Problemi correlati