Storia
La mia azienda invia una newsletter settimanale a tutti i membri dell'azienda. In queste newsletter è incluso un indovinello, insieme a uno shoutout a chiunque in azienda sia stato il primo a inviare e-mail / fornire una soluzione all'enigma della scorsa settimana. La maggior parte di questi indovinelli sono piuttosto banali e onestamente piuttosto noiosi per un'azienda tecnologica, ma ce n'è stato uno, diversi mesi fa, che ha attirato la mia attenzione.
The Original Riddle:
Data la forma seguente:
Hai i numeri naturali da 1 a 16. Adattali tutti in questa forma, in modo che tutte le righe contigue e le colonne contigue si sommino a 29.
Ad esempio, una di queste soluzioni a questo puzzle (che era la soluzione "canonica" che ho inviato alla newsletter) era la seguente:
Tuttavia, nel corso della risoluzione, ho trovato alcune informazioni piuttosto interessanti:
- Esistono molte più soluzioni rispetto a quella; in effetti, ci sono 9.368 soluzioni.
- Se si espande il set di regole per richiedere solo che righe e colonne siano uguali tra loro, non necessariamente 29, si ottengono 33.608 soluzioni:
- 4.440 soluzioni per un importo di 27.
- 7.400 soluzioni per un importo di 28.
- 9.368 soluzioni per un importo di 29.
- 6.096 Soluzioni per un importo di 30.
- 5.104 Soluzioni per un importo di 31.
- 1.200 soluzioni per un totale di 32.
Quindi io e i miei colleghi (sebbene per lo più solo il mio manager, dato che era l'unica persona diversa da me con abilità di programmazione "Scopo generale") ci siamo lanciati in una sfida, che è durata per la maggior parte del mese - abbiamo avuto un altro lavoro effettivo- obblighi correlati a cui dovevamo attenerci: per provare a scrivere un programma che trovasse ogni singola soluzione nel modo più veloce possibile.
Statistiche originali
Il primo programma che ho scritto per risolvere il problema ha semplicemente verificato più volte soluzioni casuali e si è fermato quando ha trovato una soluzione. Se hai fatto un'analisi matematica su questo problema, probabilmente già sai che questo non avrebbe dovuto funzionare; ma in qualche modo sono stato fortunato, e il programma ha impiegato solo un minuto per trovare un'unica soluzione (quella che ho pubblicato sopra). Le ripetute esecuzioni del programma richiedevano spesso fino a 10 o 20 minuti, quindi ovviamente questa non era una soluzione rigorosa al problema.
Sono passato a una soluzione ricorsiva che ha ripetuto ogni possibile permutazione del puzzle e ho scartato molte soluzioni contemporaneamente eliminando le somme che non si stavano sommando. IE se la prima riga / colonna che stavo confrontando non fosse già uguale, potrei smettere di controllare immediatamente quel ramo, sapendo che nient'altro permutato nel puzzle lo cambierebbe.
Usando questo algoritmo, ho ottenuto il primo successo "corretto": il programma potrebbe generare e sputare tutte le 33.608 soluzioni in circa 5 minuti.
Il mio manager aveva un approccio diverso: sapendo in base al mio lavoro che le uniche soluzioni possibili avevano somme di 27, 28, 29, 30, 31 o 32, scrisse una soluzione multi-thread che controllava possibili somme solo per quei valori specifici. È riuscito a far funzionare il suo programma in soli 2 minuti. Così ho ripetuto di nuovo; Ho sommato tutte le possibili somme di 3/4 cifre (all'inizio del programma; viene conteggiato nel tempo di esecuzione totale) e ho usato la "somma parziale" di una riga per cercare il valore rimanente in base a una riga precedentemente completata, anziché testare tutti i valori rimanenti e ridurre il tempo a 72 secondi. Quindi, con una certa logica multi-threading, l'ho ridotto a 40 secondi. Il mio manager ha portato a casa il programma, ha eseguito alcune ottimizzazioni su come il programma è stato eseguito e lo ha ridotto a 12 secondi. Ho riordinato la valutazione delle righe e delle colonne,
Uno dei due più veloci tra i nostri programmi dopo un mese è stato di 0,15 secondi per il mio manager e 0,33 secondi per me. Alla fine ho sostenuto che il mio programma era più veloce, poiché il programma del mio manager, sebbene trovasse tutte le soluzioni, non le stesse stampando in un file di testo. Se aggiungeva quella logica al suo codice, spesso impiegava fino a 0,4-0,5 secondi.
Da allora abbiamo permesso alla nostra sfida intra-personale di sussistere, ma ovviamente rimane la domanda: questo programma può essere reso più veloce?
Questa è la sfida che porterò a voi ragazzi.
La tua sfida
I parametri su cui abbiamo lavorato hanno rilassato la regola della "somma di 29" invece di "tutte le somme di righe / colonne uguali" e imposterò questa regola anche per voi. La sfida, quindi, è: scrivere un programma che trovi (e stampa!) Tutte le soluzioni a questo indovinello nel più breve tempo possibile. Ho intenzione di fissare un limite alle soluzioni presentate: se il programma impiega più di 10 secondi su un computer relativamente decente (<8 anni), probabilmente è troppo lento per essere conteggiato.
Inoltre, ho alcuni bonus per il puzzle:
- Puoi generalizzare la soluzione in modo che funzioni per qualsiasi set di 16 numeri, non solo
int[1,16]
? Il punteggio di tempo verrà valutato in base al numero di prompt iniziale impostato, ma passato attraverso questo codice. (-10%) - Riesci a scrivere il codice in modo che gestisca e risolva con garbo con numeri duplicati? Non è così semplice come potrebbe sembrare! Le soluzioni "visivamente identiche" dovrebbero essere uniche nel set di risultati. (-5%)
- Riesci a gestire numeri negativi? (-5%)
Puoi anche provare a generare una soluzione che gestisca i numeri in virgola mobile, ma ovviamente non essere scioccato se fallisce completamente. Se trovi una soluzione solida, potrebbe valere un grande bonus!
A tutti gli effetti, le "rotazioni" sono considerate soluzioni uniche. Quindi una soluzione che è solo una rotazione di una soluzione diversa conta come propria soluzione.
Gli IDE che sto lavorando sul mio computer sono Java e C ++. Posso accettare risposte da altre lingue, ma potrebbe essere necessario fornire anche un collegamento a dove posso ottenere un ambiente di runtime facile da configurare per il tuo codice.