Come dimostrare che l'algoritmo goloso è corretto


29

Ho un algoritmo avido che sospetto possa essere corretto, ma non ne sono sicuro. Come posso verificare se è corretto? Quali sono le tecniche da utilizzare per dimostrare che un algoritmo avido è corretto? Ci sono modelli o tecniche comuni?

Spero che questo diventerà una domanda di riferimento che può essere usata per indicare ai principianti; da qui il suo ambito più ampio del solito. Prestare attenzione a fornire risposte generali e presentate in modo didattico che sono illustrate da almeno un esempio, ma che coprono comunque molte situazioni. Grazie!



Possiamo dimostrare che un algoritmo goloso è corretto usando un matroid o un greedoid?
zdm

Risposte:


24

Alla fine, avrai bisogno di una prova matematica della correttezza. Prenderò alcune tecniche di prova per quello qui sotto, ma prima, prima di immergermi in questo, lascia che ti faccia risparmiare un po 'di tempo: prima di cercare una prova, prova i test casuali.

Test casuali

Come primo passo, ti consiglio di usare test casuali per testare il tuo algoritmo. È incredibile quanto sia efficace: nella mia esperienza, per algoritmi avidi, i test casuali sembrano irragionevolmente efficaci. Dedica 5 minuti a codificare il tuo algoritmo e potresti risparmiarti un'ora o due cercando di elaborare una prova.

L'idea di base è semplice: implementa il tuo algoritmo. Inoltre, implementa un algoritmo di riferimento che sai essere corretto (ad esempio, uno che tenta esaurientemente tutte le possibilità e prende il meglio). Va bene se l'algoritmo di riferimento è asintoticamente inefficiente, poiché lo eseguirai solo su piccole istanze problematiche. Quindi, genera in modo casuale un milione di piccole istanze di problema, esegui entrambi gli algoritmi su ciascuno e controlla se il tuo algoritmo candidato fornisce la risposta corretta in ogni caso.

Empiricamente, se il tuo algoritmo goloso candidato non è corretto, in genere lo scoprirai spesso durante i test casuali. Se sembra essere corretto su tutti i casi di test, dovresti passare al passaggio successivo: trovare una prova matematica della correttezza.

Prove matematiche di correttezza

OK, quindi dobbiamo dimostrare che il nostro avido algoritmo è corretto: che produce la soluzione ottimale (o, se ci sono più soluzioni ottimali ugualmente buone, che ne produce una).

Il principio di base è intuitivo:

Principio: se non fai mai una scelta sbagliata, farai OK.

Gli algoritmi greedy di solito implicano una sequenza di scelte. La strategia di prova di base è che proveremo a dimostrare che l'algoritmo non fa mai una scelta sbagliata. Gli algoritmi greedy non possono tornare indietro - una volta che fanno una scelta, sono impegnati e non annulleranno mai quella scelta - quindi è fondamentale che non facciano mai una scelta sbagliata.

Quale sarebbe una buona scelta? Se esiste un'unica soluzione ottimale, è facile vedere quale sia una buona scelta: qualsiasi scelta identica a quella fatta dalla soluzione ottimale. In altre parole, proveremo a dimostrare che, in qualsiasi fase dell'esecuzione degli algoritmi avidi, la sequenza di scelte fatte finora dall'algoritmo corrisponde esattamente a un prefisso della soluzione ottimale. Se esistono più soluzioni ottimali ugualmente valide, una buona scelta è quella coerente con almeno una delle optima. In altre parole, se la sequenza di scelte dell'algoritmo finora corrisponde a un prefisso di una delle soluzioni ottimali, tutto va bene finora (nulla è ancora andato storto).

Per semplificare la vita ed eliminare le distrazioni, concentriamoci sul caso in cui non vi siano legami: esiste un'unica soluzione ottimale unica. Tutti i macchinari riporteranno il caso in cui possono esserci più optima ugualmente buoni senza modifiche fondamentali, ma è necessario prestare maggiore attenzione ai dettagli tecnici. Inizia ignorando quei dettagli e concentrandoti sul caso in cui la soluzione ottimale è unica; che ti aiuterà a concentrarti su ciò che è essenziale.

C'è un modello di prova molto comune che usiamo. Lavoreremo sodo per dimostrare la seguente proprietà dell'algoritmo:

Reclamo: Sia la soluzione emessa dall'algoritmo e sia la soluzione ottimale. Se è diverso da , allora ci possono modificare per ottenere un'altra soluzione che è diverso da e rigorosamente meglio di .SOSOOOOO

Nota perché questo è utile. Se l'affermazione è vera, ne consegue che l'algoritmo è corretto. Questa è sostanzialmente una prova di contraddizione. O è uguale a oppure è diverso. Se è diverso, allora possiamo trovare un'altra soluzione che è strettamente migliore di - ma questa è una contraddizione, poiché abbiamo definito come la soluzione ottimale e non può esserci alcuna soluzione migliore di quella. Quindi siamo costretti a concludere che non può essere diverso da ; deve sempre essere uguale aSOOOOSOSO, cioè l'algoritmo goloso produce sempre la soluzione corretta. Se siamo in grado di provare la rivendicazione di cui sopra, allora abbiamo dimostrato che il nostro algoritmo è corretto.

Belle. Quindi, come possiamo dimostrare la richiesta? Pensiamo a una soluzione come un vettore che corrisponde alla sequenza di scelte fatte dall'algoritmo e allo stesso modo, pensiamo alla soluzione ottimale come un vettore corrispondente alla sequenza di scelte che porterebbe ad . Se è diverso da , deve esistere un indice cui ; ci concentreremo sul più piccolo tale . Quindi, modificheremo cambiando un po 'S(S1,,Sn)nO(O1,,On)OSOiSiOiiOOi° posizione per abbinare , cioè, faremo modificare la soluzione ottimale cambiando la esima scelta per il prescelto dall'algoritmo greedy, e poi ci dimostriamo che questo porta ad una soluzione ancora migliore. In particolare, definiremo come qualcosa del genereSiOiO

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

tranne che spesso dovremo modificare leggermente la parte per mantenere la coerenza globale. Parte della strategia di dimostrazione comporta una certa intelligenza nel definire appropriato. Quindi, la carne della dimostrazione utilizzerà in qualche modo i fatti relativi all'algoritmo e al problema per dimostrare che è strettamente migliore di ; ecco dove avrai bisogno di approfondimenti specifici del problema. Ad un certo punto, dovrai immergerti nei dettagli del tuo problema specifico. Ma questo ti dà un senso della struttura di una tipica prova di correttezza per un algoritmo avido.Oi+1,Oi+2,,OnOOO

Un semplice esempio: sottoinsieme con somma massima

Questo potrebbe essere più facile da capire lavorando attraverso un semplice esempio in dettaglio. Consideriamo il seguente problema:

Input: un set di numeri interi, un numero intero Output: un set di dimensione cui somma è il più grande possibileUk
SUk

C'è un algoritmo naturale avido per questo problema:

  1. Impostare .S:=
  2. Per : i:=1,2,,k
    • Diciamo tramite il maggior numero di che non è stato ancora scelto (cioè, l' esimo numero più grande ). Aggiungere a .xiUiUxiS

Test casuali suggeriscono che ciò fornisce sempre la soluzione ottimale, quindi proviamo formalmente che questo algoritmo è corretto. Nota che la soluzione ottimale è unica, quindi non dovremo preoccuparci dei legami. Dimostriamo l'affermazione sopra descritta:

Reclamo: Sia la soluzione emessa da questo algoritmo sugli input e la soluzione ottimale. Se , allora possiamo costruire un'altra soluzione la cui somma è ancora più grande di .SU,kOSOOO

Prova. Assumo , e lasciare che essere l'indice della prima iterazione dove . (Tale indice deve esistere, dal momento che abbiamo assunto e dalla definizione dell'algoritmo abbiamo .) Dal momento che (per ipotesi) è minima, abbiamo deve avere e, in particolare, ha la forma , in cui i numeri sono elencati in ordine decrescente. Osservando come l'algoritmo sceglieSOixiOiSOS={x1,,xk}ix1,,xi1OOO={x1,x2,,xi1,xi,xi+1,,xn}x1,,xi1,xi,,xnx1,,xi, vediamo che dobbiamo avere per tutto . In particolare, . Quindi, definiamo , ovvero otteniamo cancellando l' numero in e aggiungendo . Ora la somma degli elementi di è la somma degli elementi di più e , quindi la somma di è strettamente più grande della somma diQuesto dimostra l'affermazione. xi>xjjixi>xiO=O{xi}{xi}OiOxiOOxixixixi>0OO

L'intuizione qui è che se l'algoritmo avido fa una scelta incompatibile con , allora possiamo dimostrare che potrebbe essere ancora migliore se fosse modificato per includere l'elemento scelto dall'algoritmo avido in quella fase. Poiché è ottimale, non ci può essere alcun modo per renderlo ancora migliore (sarebbe una contraddizione), quindi l'unica possibilità rimasta è che la nostra ipotesi fosse sbagliata: in altre parole, l'algoritmo avido non farà mai una scelta che sia in contrasto con .OOOO

Questo argomento viene spesso chiamato argomento di scambio o lemma di scambio . Abbiamo trovato il primo posto in cui la soluzione ottimale differisce dalla soluzione avida e abbiamo immaginato di scambiare quell'elemento di con la corrispondente scelta avida (scambiato con ). Alcune analisi hanno dimostrato che questo scambio può solo migliorare la soluzione ottimale, ma per definizione la soluzione ottimale non può essere migliorata. Quindi l'unica conclusione è che non ci deve essere alcun luogo in cui la soluzione ottimale differisce dalla soluzione golosa. Se hai un problema diverso, cerca opportunità per applicare questo principio di scambio nella tua situazione specifica.Oxixi


Questa è una vecchia domanda, ma è il primo risultato in Google per me. La linea then we can tweak O to get another solution O∗ that is different from O and strictly better than Omi confonde. Se esistono più soluzioni ottimali, è possibile avere S != Oed entrambi essere comunque ottimali; possiamo modificare O per essere "più simile a" S (creando O ∗) e tuttavia essere buono come (non strictly better than) O.
citelao

@citelao, mi dispiace sapere che ti ha confuso. Ahimè, non sono sicuro di come spiegarlo più chiaramente. Sì, potrebbero esserci più soluzioni ottimali, tutte con lo stesso valore. È corretto. Ciò che hai scritto e quello che ho scritto sono entrambi validi; non c'è contraddizione. La differenza è che ciò che hai scritto non aiuta a dimostrare un algoritmo avido corretto; quello che ho scritto fa. Posso solo suggerire di rileggere ciò che ho scritto di nuovo e vedere se riesci a capire come ciò che ho scritto sia utile. Se ciò non aiuta, forse trovare un altro tipo di scrittura. Mi rendo conto che è complicato e confuso.
DW

1
Grazie per la risposta rapida! Ho perso il punto in cui ti concentri sulla dimostrazione dell'algoritmo, se ce n'è solo a single, unique optimal solution. Poiché questa domanda riguarda la dimostrazione corretta di qualsiasi algoritmo avido, vorrei fornire una risposta per i casi in cui possono esistere più soluzioni ottimali. È passato un po 'di tempo da quando ho studiato tutto questo, ma non è sufficiente per dimostrare che è possibile scambiare ogni elemento O_i in qualsiasi soluzione ottimale O che differisce dall'alg. soluzione S con S_i e hai ancora una soluzione O 'che non è peggio di O?
citelao,

@citelao, la tecnica si applica anche ai casi in cui esistono molteplici soluzioni ottimali. Ho suggerito di concentrarmi sul caso in cui la soluzione ottimale è unica solo perché, la prima volta che vedi questo, è più facile capire come funzionano queste prove in quel contesto. Ma la stessa strategia funziona anche se ci sono più soluzioni ottimali. Suggerisco di studiarlo, assicurandoti di capire come funziona quando esiste un'unica soluzione ottimale, quindi di applicarlo al caso generale. Inoltre penso che possa aiutarti a studiare alcune prove di esempio per algoritmi avidi.
DW

Per rispondere a quest'ultima domanda, no, non è sufficiente. Ciò non dimostra che S sia ottimale. (Se chiedi solo che O 'non sia peggiore di O, ci sono casi in cui S non è ottimale ma è possibile fare quel tipo di scambio. Quindi dimostrando che è possibile ottenere una O' che non è peggio di O non prova nulla sul fatto che S sia ottimale e non dimostri che l'algoritmo avido sia corretto. Suggerisco di studiare un po 'di più il metodo descritto nella risposta. È difficile. La prova della contraddizione è spesso difficile da capire.)
DW

14

Userò il seguente algoritmo di ordinamento semplice come esempio:

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

Per dimostrare la correttezza, utilizzo due passaggi.

  • Per prima cosa mostro che l'algoritmo termina sempre.
  • Quindi mostro che la soluzione in cui termina è quella che desidero.

Per il primo punto, scelgo una funzione di costo adatta per la quale posso dimostrare che l'algoritmo lo migliora in ogni passaggio.

Per questo esempio scelgo il numero di inversioni nell'elenco di input. Un'inversione in un elenco è una coppia di voci , tale che ma . Il numero di inversioni è sempre non negativo e un elenco ordinato ha 0 inversioni.AA[i]A[j]A[i]>A[j]i<j

Scambiando chiaramente due elementi adiacenti , che sono nell'ordine sbagliato rimuove l'inversione ma lascia invariata qualsiasi altra inversione. Quindi il numero di inversioni è ridotto in ogni iterazione.A[i]A[i+1]A[i],A[i+1]

Ciò dimostra che l'algoritmo alla fine termina.

Il numero di inversioni in un elenco ordinato è 0. Se tutto va bene, l'algoritmo ridurrà il numero di inversioni fino a 0. Dobbiamo solo dimostrare che non si blocca in un minimo locale.

Di solito lo provo per contraddizione. Presumo che l'algoritmo si sia arrestato, ma la soluzione non è corretta. Nell'esempio, ciò significa che l'elenco non è stato ancora ordinato, ma non ci sono elementi adiacenti nell'ordine sbagliato.

Se l'elenco non è ordinato, devono essere presenti almeno due elementi che non si trovano nella posizione corretta. Lascia che e , , siano due di questi elementi se la differenza tra e è minima. Poiché l'algoritmo non si è arrestato, non sono adiacenti, quindi . Poiché abbiamo assunto la minimalità, e , ma poi e abbiamo una contraddizione.A [ j ] i < j A [ i ] > A [ j ] i j i + 1 < j A [ i ] < A [ i + 1 ] A [ i + 1 ] < A [ j ] A [ i ] < A [ j ]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]

Ciò dimostra che l'algoritmo si interrompe solo quando l'elenco è ordinato. E quindi abbiamo finito.


Le tecniche spiegate sono così generali che praticamente non hanno nulla di particolare sull'algoritmo goloso, argomento di questa domanda.
Apass
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.