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 .SOSOOO∗OO
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 aSOO∗OOSOSO, 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)OSOiSi≠OiiOOi° 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,…,Oi−1,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,…,OnO∗O∗O
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
S⊆Uk
C'è un algoritmo naturale avido per questo problema:
- Impostare .S:=∅
- 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,kOS≠OO∗O
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 sceglieS≠Oixi∉OiS≠OS={x1,…,xk}ix1,…,xi−1∈OOO={x1,x2,…,xi−1,x′i,x′i+1,…,x′n}x1,…,xi−1,x′i,…,x′nx1,…,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>x′jj≥ixi>x′iO=O∪{xi}∖{x′i}O∗iOxiO∗Oxi−x′ixi−x′i>0O∗O■
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.Ox′ixi