Otto monete per il re giusto


22

Questa è una "controparte" di un altro enigma, otto monete per il re giusto su Puzzling.SE.

Puoi leggere il puzzle sopra per lo sfondo. I dettagli su questo puzzle sono i seguenti.

Viene creato un set di 8 tipi di monete con valori diversi, il re vuole che tu scopra il massimo N in modo tale che qualsiasi numero di prezzo da 0 a N possa essere pagato con una combinazione non più di 8 monete e senza spese.

Ad esempio, (tratto dalla risposta di Glorfindel). Se viene fornito un insieme di monete con valori 1, 2, 5, 13, 34, 89, 233, 610, il programma dovrebbe generare 1596, poiché ogni numero compreso tra 0 e 1596 (compreso) può essere rappresentato dalla somma di non più di 8 numeri dall'elenco indicato (i numeri possono essere ripetuti), mentre 1597 non può essere rappresentato in questo modo.

In modo matematico, se l'ingresso è un insieme S costituito da 8 numeri interi positivi, l'uscita N desiderata soddisfa che per qualsiasi numero n compreso tra 0 e N, esiste x1, x2, x3, ..., x8 tale che

x1+x2+...+x8=nandx1,x2,...,x8{0}S

Il tuo obiettivo è scrivere un programma, una funzione o uno snippet che accetta 8 numeri come input e genera l'N massimo come descritto sopra.

Regole:

  • I / O flessibile consentito, in modo che il tuo programma possa prendere l'input in qualsiasi forma più adatta. Si può presumere che i numeri di input siano ordinati nel modo più adatto al proprio programma.
    • Indicalo nella risposta se il programma dipende dall'ordine di input
  • L'input è un insieme di 8 diversi numeri interi positivi (senza zeri). L'output è un numero intero non negativo.
    • Nel caso in cui non ci sia 1 nel set di input, il programma dovrebbe generare 0 perché qualsiasi numero compreso tra 0 e 0 soddisfa il requisito.
    • In caso di input non valido (il set contiene zero, numeri negativi o duplicati), il programma può fare qualsiasi cosa.
  • Sono vietate le scappatoie standard.
  • Il programma dovrebbe essere eseguito in pochi minuti su un computer moderno.

Casi di test (principalmente tratti dalle risposte sotto la domanda collegata su Puzzling):

[1, 2, 3, 4, 5, 6, 7, 8] => 64
[2, 3, 4, 5, 6, 7, 8, 9] => 0
[1, 3, 4, 5, 6, 7, 8, 9] => 72
[1, 2, 5, 13, 34, 89, 233, 610] => 1596
[1, 5, 16, 51, 130, 332, 471, 1082] => 2721
[1, 6, 20, 75, 175, 474, 756, 785] => 3356

Questo è un , quindi vince il programma o lo snippet più breve in ogni lingua!


1
Bel puzzle, ma personalmente penso che alcuni altri casi di test sarebbero utili per testare i nostri invii.
Mr. Xcoder il

Non sarebbe meglio rendere la dimensione di input un parametro? Gli approcci alla forza bruta faranno fatica con l'8
Luis Mendo il

1
@iBug Quindi la solita regola è qualcosa come "le presentazioni dovrebbero essere eseguite in un minuto in un computer moderno". È confuso, ma di solito abbastanza buono, perché la differenza tra forza bruta e approcci efficienti è molto grande
Luis Mendo il

1
La forza bruta è ancora possibile con il limite di tempo di "pochi minuti". Una versione leggermente modificata della mia risposta esegue l'ultimo test case in 1m20s sul mio laptop di 7 anni.
nimi,

1
@Arnauld Clarified
iBug il

Risposte:



9

Gelatina , 12 byte

œċⱮ8Ẏ§ṢQJƑƤS

Provalo online!

Richiede in media ~ 3,7 secondi per eseguire tutti i casi di test su TIO sul mio telefono, quindi sorprendentemente è abbastanza veloce.

Spiegazione

œċⱮ8Ẏ§ṢQJƑƤS     Monadic link / Full program.
  Ɱ8             Promote 8 to [1 ... 8] and for each value k:
œċ                    Generate all combinations of k elements from the list.
    Ẏ§           Tighten, then sum. Flatten to a 2D list then sum each.
      ṢQ         Sort the result and remove equal entries.
        JƑƤ      For each prefix of this list, return 1 if it is equal to its length range, 0 otherwise.
           S     Finally, sum the result (counts the 1's which is equivalent to what is being asked).

7

Haskell, 56 50 byte

g c=[x|x<-[1..],all((/=x).sum)$mapM(0:)$c<$c]!!0-1

Provalo online!

Un approccio a forza bruta. Aggiungi 0all'elenco delle monete e prova tutte le combinazioni di 8 scelte. Trova il primo numero nche non è uguale alla somma di nessuna delle scelte e ritorno n-1.

Richiede circa 5m30s per [1, 2, 5, 13, 34, 89, 233, 610]il mio hardware portatile di 7 anni.

Modifica: -6 byte grazie a @ Ørjan Johansen

Una versione ancora più breve (-2 byte, sempre grazie a @ Ørjan Johansen) è

Haskell, 48 byte

g c=[x|x<-[1..],all((/=x).sum)$mapM(:0:c)c]!!0-1

ma utilizza molta più memoria e si imbatte in pesanti paging sulla mia macchina e non termina "in pochi minuti".


1
È possibile utilizzare mapM(0:)$c<$c. (In effetti mapM(:0:c)cdovrebbe funzionare, ma va in timeout su TIO per il caso di test fornito.)
Ørjan Johansen,

4

Gelatina , 9 byte

Żœċ8§ḟ’$Ṃ

Provalo online!

Come funziona

Żœċ8§ḟ’$Ṃ  Main link. Argument: A (array)

Ż          Prepend a 0 to A.
 œċ8       Take all combinations of length 8, with repetitions.
    §      Take the sum of each combination.
       $   Combine the two links to the left into a monadic chain.
      ’      Decrement all sums.
     ḟ       Filterfalse; keep only sums that do not appear in the decremented sums.
        Ṃ  Take the minimum.

2
Żṗ8§ḟ’$Ṃsalva un byte, ma non sono sicuro che 8,5 minuti contino come pochi .
Dennis,


4

JavaScript (ES6),  100 88 80  76 byte

Questa è essenzialmente una ricerca della forza bruta, ma migliorata con la potatura per accelerarla. Il tempo medio di esecuzione per i casi di test è quasi 1 secondo su TIO.

Presuppone che l'array di input sia ordinato dal più alto al più basso.

a=>[...Array(a[0]*9)].findIndex(g=(i=8,s)=>s*i>0?a.every(x=>g(i-1,s-x)):s)-1

Provalo online!

Commentate

a =>                      // a[] = input array
  [...Array(a[0] * 9)]    // create an array of 9 * max(a) entries
  .findIndex(             // find the position of the first truthy result
    g = (i = 8, s) =>     // g = recursive function taking a counter i, initialized to 8
                          //     and a sum s, initialized to the position in the above array
      s * i > 0 ?         //   if s is positive and i is not equal to 0:
        a.every(x =>      //     for each value x in a[]:
          g(i - 1, s - x) //       do a recursive call with i - 1 and s - x
        )                 //     end of every()
      :                   //   else:
        s                 //     yield s (s = 0 means success and makes findIndex go on)
  ) - 1                   // end of findIndex(); decrement the result


3

Pari / GP , 57 byte

a->n=-1;while(polcoeff((1+sum(i=1,8,x^a[i]))^8,n++),);n-1

Provalo online!


sta usando questa funzione generatrice?
don luminoso

1
@donbright Sì.
alephalpha

1
è fantastico .. una delle poche risposte non forzare brutalmente la soluzione. molte lingue probabilmente non hanno caratteristiche polinomiali simboliche integrate. Pari GP è fantastico.
don luminoso

2

Python 2 , 125 115 111 byte

lambda c:sum(i==j for i,j in enumerate(sorted(set(map(sum,product([0]+c,repeat=8))))))-1
from itertools import*

Provalo online!

Si aspetta un elenco di numeri interi come input.

Spiegazione:

# an anonymous function
lambda c:
                                                          # get all length-8 combinations of values, from (0,0,0,0,0,0,0,0) to (8,8,8,8,8,8,8,8)
                                                          # zero is added to ensure that combinations of fewer than 8 coins are represented Ex:(1,0,0,0,0,0,0,0)
                                                          product([0]+c,repeat=8)
                                                  # for each combination, sum the values
                                                  map(sum,.......................)
                                       # get unique values, then sort them smallest to largest
                                       sorted(set(................................))
             # for each index, value pair, return if the index is equal to the value
             i==j for i,j in enumerate(.............................................)
         # in Python arithmetic, False is 0 and True is 1. So, count how many items match their index.
         # Since zero was added to the list, there will always be one extra match (0==0). So offset by one.
         sum(........................................................................)-1
from itertools import*

2

Perl6, 65 63 41 byte ( 39 37 caratteri)

{@_=(0,|@_)X+(0,|@_)for ^3;($_ if $_==$++for @_.sort.unique)-1}

Provalo online!

Questo è un blocco anonimo che ottiene i suoi dati come un array. Il (0,|@_)è un modo rapido per aggiungere un 0a @_, e anche se è fatto due volte, è ancora un po 'più corto @_.push: 0;che avrebbe poi bisogno di spazi dopo il _. Questo è un approccio a forza bruta che si fonde un po 'sul fatto che sono 8 combinazioni. Dopo l'aggiunta incrociata, viene creato un elenco anonimo per i valori sequenziali. Con gli operatori matematici, gli elenchi valutano la loro lunghezza, quindi -1 prende il doppio dovere: contabilizzando lo 0 e costringendo a Int.

Questo può prendere il suo tempo dolce, ma cambiando uno o entrambi (0,|@_)alla (0,|@_.unique)prima del primo forche può essere accelerato notevolmente. Ciò aggiunge +7 (runtime <60s) o +14 (runtime <10s) al punteggio se ritieni che il primo sia troppo lento (l'ho fatto per il codice collegato per evitare timeout dopo 60 secondi).

Modifica: JoKing nei commenti lo ha migliorato (stessa idea, cross add, quindi restituisce l'ultimo risultato consecutivo) a un sorprendente 39 caratteri (41 byte):

{(@_=@_ X+0,|@_)xx 3;first *+1@_,^∞}

Provalo online!

La tabulazione finale non ha bisogno di uno 0, risparmiando pochi byte semplicemente aggiungendo 0 in una volta. I xx 3imita il ciclo for (formaggi ancora sulle monete essendo una potenza di 2). Il firstsottotitolo restituisce il primo numero nell'elenco infinito 0..*( ^Infè anche possibile, ma non risparmia spazio) il cui +1non è un membro dell'elenco aggiunto incrociato. Come il mio, è lento, quindi aggiungi +7 per un uniquedopo che il primo è uguale se ritieni che sia troppo lento per le linee guida.


1
48 byte . Tecnicamente, uniquenon è necessario, ma lo accelera molto
Jo King il

@JoKing nice, non so perché non ho pensato di usare xx. Sapevo che doveva esserci un modo per eseguire la tabulazione finale in un modo molto più breve usando le funzioni impostate, ma il mio cervello non funzionava.
user0721090601

Il xx 1dovrebbe esserexx 3
Jo Re

@JoKing fixed. Inoltre ho capito che due caratteri (ma nessun byte) possono essere salvati usando^∞
user0721090601

In realtà, puoi salvare alcuni byte con (1...*∉@_)-1invece di usare first, (che mi rendo conto che è lo stesso metodo che ho usato qui )
Jo King

1

JavaScript (Node.js) , 171 145 115 byte

f=(s,n=3)=>n?f(s=new Set(a=[0,...s]),n-1,a.map(m=>a.map(n=>s.add(m+n)))):Math.min(...[...s].filter(m=>!s.has(m+1)))

Provalo online! Python 3 di Port of @ Mark. 108 byte in Firefox 30-57:

f=(s,n=3)=>n?f(new Set((for(n of s=[0,...s])for(m of s)n+m)),n-1):Math.min(...[...s].filter(m=>!s.has(m+1)))

1

Wolfram Language (Mathematica) , 46 byte

0//.x_/;Min[Tr/@FrobeniusSolve[#,x+1]]<9:>x+1&

Provalo online!

Approccio a forza bruta: controlla i numeri interi che contano verso l'alto fino a raggiungere un valore che non può essere pagato in 8 monete. Molto, molto lento (tio timeout), ma sono abbastanza sicuro che la condizione sia corretta.


0

Pulito , 161 byte

import StdEnv,Data.List
$l=:[1:_]#k=sort(nub(map sum(iter 8(concatMap(\[h:t]=[[e,h:t]\\e<-[0:l]|e>=h]))[[0]])))
=length(takeWhile((>=)1)(zipWith(-)(tl k)k))
$_=0

Provalo online!

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.