2014-10-08 15 views
5

Codilità, lezione 14, task TieRopes (https://codility.com/demo/take-sample-test/tie_ropes). In breve, il problema è di partizionare una lista di interi positivi A nel numero massimo di sottolisti (contigui) con somma almeno K.Perché l'algoritmo goloso è ottimale?

Ho appena trovato una soluzione avida perché è il nome della lezione. Supera tutti i test ma non so perché sia ​​una soluzione ottimale (se è ottimale).

int solution(int K, vector<int> &A) { 
    int sum = 0, count = 0; 
    for (int a : A) 
    { 
     sum += a; 
     if (sum >= K) 
     { 
      ++count; 
      sum = 0; 
     } 
    } 
    return count; 
} 

Qualcuno può dirmi se e perché questa soluzione è ottimale?

+2

Il modello normale per dimostrare un algoritmo goloso ottimale è quello di (1) porre un caso in cui la golosità non produce un risultato ottimale; (2) guarda al primo posto dove la sua soluzione e la soluzione ottimale divergono; e (3) dimostrare che quel luogo non può esistere. Dimostrazione per contraddizione. – Sneftel

+1

Per me sembra che il requisito di * contiguità * elimini già tutta la flessibilità significativa dalla soluzione di questo problema. Cioè la soluzione è ovvia e semplice: basta accumulare una partizione dall'inizio fino a ottenere 'K' e quindi avviare una nuova partizione. L'unica flessibilità che consente è di continuare ad estendere la partizione corrente quando la sua somma è già 'K', ma è immediatamente ovvio che ciò ridurrà solo la qualità della soluzione. – AnT

+0

@AndreyT Questa è la tua intuizione e probabilmente hai ragione, ma non penso che sia una prova sufficiente. – NPS

risposta

3

Forse sono ingenuo o sto facendo qualche errore qui, ma penso che non sia troppo difficile (anche se non ovvio) per vedere che l'algoritmo è davvero ottimale.

Supponiamo di avere una partizione ottimale della lista con il numero massimo di sottoliste. Puoi avere o meno tutti gli elementi della lista, ma dal momento che aggiungere un elemento a un elenco valido produce anche un elenco valido, supponiamo che qualsiasi possibile elemento "rimanente" che inizialmente non era assegnato a nessun sottolista fosse assegnato arbitrariamente a uno dei suoi sottolisti adiacenti; quindi abbiamo una partizione ottimale corretta della lista, che chiameremo P1.

Ora pensiamo alla partizione che l'algoritmo vorrebbe produrre, per esempio P2. Ci sono due cose che possono accadere per la prima sottolista in P2:

  1. Può essere uguale alla prima sottolista in P1.
  2. Può essere più breve della prima sottolista in P1.

In 1. si ripeterà il ragionamento a partire dall'elemento successivo dopo la prima sottolista. Se ogni successiva sottolista prodotta dall'algoritmo è uguale a quella in P1, allora P1 e P2 saranno uguali.

In 2. si ripeterà anche il ragionamento, ma ora è disponibile almeno un elemento "extra". Quindi, di nuovo, la prossima sottolista potrebbe:

2.1. Vai fino alla prossima sottolista in P1.
2.2. Termina prima della successiva sottolista in P1.

E ripetere. Quindi, in ogni caso, avrai almeno come molti sottolisti come P1. Il che significa che P2 è almeno valido come qualsiasi partizione dell'elenco e, in particolare, qualsiasi partizione ottimale.

Non è una dimostrazione molto formale, ma I è valido. Per favore, fai notare tutto ciò che pensi possa essere sbagliato.

+0

Questo è anche il modo in cui penso a questo problema. In sostanza, è possibile dimostrare che per ogni soluzione ottimale che ha k sottoliste, la soluzione avida ha almeno k sottoliste le cui prime posizioni sono ciascuna <= le prime posizioni corrispondenti nella soluzione ottimale. (Un errore di battitura: dovrebbe essere "Può essere più breve della prima sottolista in P1", non "... in P2".) –

+0

@j_random_hacker grazie! fisso – jdehesa

1

Ecco le idee che portano a una dimostrazione formale.

  1. Se A è un suffisso di B, allora la dimensione massima della partizione per A è inferiore o uguale alla dimensione massima partizione per B, perché possiamo estendere il primo elenco secondario di una partizione di A per includere il nuovi elementi senza diminuire la sua somma.

  2. Ogni prefisso corretto di ogni sottolista nella soluzione golosa corrisponde a meno di K.

  3. Non c'è motivo di avere spazi vuoti, perché possiamo aggiungere gli elementi mancanti ad una lista adiacente (ho pensato che la mia formulazione della domanda avesse escluso questa possibilità per definizione, ma lo dirò comunque).

La prova convenzionale può essere effettuata per induzione per dimostrare che, per ogni intero non negativo i, esiste una soluzione ottimale che concorda con la soluzione avido sui primi i sottoliste di ciascuno. Ne consegue che, quando i è sufficientemente grande, l'unica soluzione che è d'accordo con l'avidità è avida, quindi la soluzione golosa è ottimale.

La base i = 0 è banale, poiché una soluzione ottimale arbitraria farà. Il passo induttivo consiste nel trovare una soluzione ottimale che sia d'accordo con le avide sulle prime sottoliste i e poi ridurre la sottolista i+1 in modo che corrisponda alla soluzione avida (dall'osservazione 2, stiamo davvero riducendo quella sottolista, poiché inizia nella stessa posizione di avidi: con l'osservazione 1, possiamo estendere la sottolista i+2 della soluzione ottimale corrispondentemente).

+0

Non seguo il punto n. 2, ho paura - o perché deve essere vero, o perché è utile! Il resto ha senso, ma penso che sia anche necessario dire esplicitamente che il primo sottolista in qualsiasi soluzione ottimale non può essere più breve del primo sottolista nella soluzione golosa, per spiegare perché l'unico caso che dobbiamo affrontare nel passaggio induttivo è ridurre la sottolista della soluzione ottimale (i + 1) (cioè perché non abbiamo mai bisogno di coltivarli). –

+0

@j_random_hacker Questo era il mio significato inteso e sono d'accordo sul fatto che il testo precedente fosse scadente. –

+0

Per me è più chiaro ora, grazie. FWIW Non penso che sia necessario il punto 3; la "partizione" nella domanda dell'OP mi dice che nessuna soluzione è autorizzata a contenere un'interruzione, e le lacune non appaiono durante la costruzione avida. (Sono anche sconcertato dal fatto che dasblinkenlights ne abbia parlato). Mentre sto facendo il pelo nell'uovo: scrivere "solo" in "l'unica soluzione che è d'accordo con l'avidità è avida" sembra suggerire che la soluzione avida potrebbe essere unica, ma non lo è (e non ha bisogno di essere); AFAICT, tutto ciò che è necessario è trovare una soluzione ottimale corrispondente quando i = opt_number_of_sublists. –