Algoritmo con complessità O(logn)

Black27
In un esercizio è richiesto di scrivere un algoritmo in pseudo-codice che abbia come limite superiore logn.
Trovare una soluzione con costo O(n) è facile, ma O(logn) non mi viene in mente nulla (sarà l'ora!).
Potete aiutarmi a capire come risolverlo? Di seguito il testo:

Siano date n monete d'oro, tutte dello stesso peso tranne una contraffatta che pesa meno, ed una bilancia con due piatti. Disegnare un algoritmo per individuare la moneta contraffatta in al più logn pesate.

Leggendo la consegna immagino che le monete siano gli indici 1..n di un array A[1..n], dove l'indice i dell'array corrisponde al peso A. Pensavo di simulare il problema con un ciclo for da 1 a n/2, dove confronto i valori A e A[n-i] degli array (con i != n-i), e se uno è minore dell'altro la moneta i o n-i è la più leggera, ma strutturato in questo modo l'algoritmo è O(n).

Vi ringrazio anticipatamente dell'aiuto :smt023

Risposte
claudio862
Credo che con il termine "pesate" indichi "confronti". Devi scrivere un algoritmo che faccia O(log n) confronti, dove un confronto è
if (qualcosa < qualcos'altro) {
    ...
} else {
    ...
}


Quindi il trucco è calcolare il peso di sottoinsiemi di monete e confrontarli tra loro. Ti conviene prima trovare un procedimento a parole, e solo dopo trasformarlo in algoritmo. E magari all'inizio limitati al caso n pari, per poi generalizzare in seguito.

vict85
Si tratta di un classico esempio di divide-et-impera.

Se tu hai che le monete sono tutte uguali tranne una allora se tu dividi un due gruppetti allora sai che uno dei due gruppetti deve pesare meno dell'altro. A questo punto hai il problema che n potrebbe non essere divisibile per due.

Con un giochetto puoi comunque fare in modo di dividere \(\displaystyle n \) in 3 blocchetti (di cui uno più piccolo degli altri due) e confrontarli in una sola pesata. Il calcolo della complessità è una applicazione del master method (penso si chiami metodo dell'esperto in italiano) e la pesata, indipendentemente da quante monete ci metti sopra, dovrebbe essere di complessità costante (una implementazione sul computer usando array avrebbe invece una complessità lineare e a quel punto però potresti usare un semplice algoritmo di ricerca).

Black27
Innanzitutto vi ringrazio delle risposte.
Poi volevo chiedere: Come strutturo la visita? Perché non penso che le monete siano ordinate in uno specifico modo, quindi come posso applicare il divide-et-impera? Se la moneta più leggera sarà l'ultima che visito, la complessità salirebbe comunque a n o no?

claudio862
Le monete sono memorizzate in un vettore v di interi, v[ i] è il peso della moneta i.
Pesi la prima metà del vettore e la seconda metà:
pesoPrimaMetà = sum (i = 1 : n/2) v[i]
pesoSecondaMetà = sum (i = n/2+1 : n) v[i]

Queste contano come due pesate, anche se per forza di cose saranno implementate con due cicli da n/2 iterazioni.

vict85
"claudio86":
Le monete sono memorizzate in un vettore v di interi, v[ i] è il peso della moneta i.
Pesi la prima metà del vettore e la seconda metà:
pesoPrimaMetà = sum (i = 1 : n/2) v[i]
pesoSecondaMetà = sum (i = n/2+1 : n) v[i]

Queste contano come due pesate, anche se per forza di cose saranno implementate con due cicli da n/2 iterazioni.


Direi proprio di no. Se tu avessi ogni v ti basterebbe cercare il minimo, ma l'unica cosa che tu hai sono due piatti. Formalmente hai una funzione, di complessità costante, che compara due sottoinsiemi. Penso che si possa supporre che la suddivisione in sottoinsiemi sia costante.

Io lo scriverei così:
FakeCoin :: A is Set -> c is Set
begin FakeCoin
if(card A == 1) 
then 
      return A;
else
    (A,B,C) is (Set, Set, Set);
    (A,B,C) = subdivide A;
    D is Set;
    D = min A, B;
    if D == EmptySet 
    then
         return FakeCoin C;
    else
        return FakeCoin D;
    endif
endif
end FakeCoin

claudio862
"vict85":
Direi proprio di no. Se tu avessi ogni v[i ] ti basterebbe cercare il minimo, ma l'unica cosa che tu hai sono due piatti. Formalmente hai una funzione, di complessità costante, che compara due sottoinsiemi.

Beh, così sono capaci tutti :P

Dipende da quanto in dettaglio vuoi descrivere l'algoritmo. Il peso di un insieme di monete è la somma dei pesi delle singole monete. Nel mondo reale è un'operazione a costo costante ma su un computer no (per questo avevo sottolineato che ai fini dell'algoritmo i due cicli contavano come due operazioni, e come fatto notare anche da vict85).
Puoi anche vederla in un altro modo: tu non conosci i valori di v[ i], ma l'entità (funzione / classe / bilancia) che calcola il peso di insiemi di monete sì.

Comunque probabilmente il livello di dettaglio della tua soluzione è quello richiesto (però avrei evitato di dare la soluzione direttamente).

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.