Pepite di codice


18

Pepite di codice

È una situazione ipotetica in cui è venerdì sera e hai invitato i soliti compagni di golf a partecipare al tuo hobby preferito: il golf a codice. Tuttavia, poiché si tratta di un compito così drenante per il cervello, è necessario raccogliere del cibo per il cervello per il gruppo in modo da poter giocare a golf il più possibile con il proprio codice.

Ora, la merenda preferita da tutti sono le crocchette di pollo, ma c'è un problema: non esiste un unico pacchetto che copra le esigenze di tutti. Quindi, poiché sei già in vena di golf, decidi di creare un programma che capisca esattamente quali pacchetti devi acquistare per essere in grado di coprire le esigenze di tutti i Nugget.

Le dimensioni del pacchetto di crocchette di pollo sono ovunque e, a seconda di dove vivi nel mondo, cambiano anche le dimensioni standard. Tuttavia, il [luogo che serve le pepite] più vicino contiene le seguenti dimensioni di pacchetti di pepite :

4, 6, 9, 10, 20, 40

Ora potresti notare che non puoi ordinare determinate combinazioni di pepite. Ad esempio, i 11nugget non sono possibili, poiché non esiste una combinazione uguale a 11esattamente. Tuttavia, puoi ottenere 43ottenendo 1 pacchetto di 20, 1 pacchetto di 10, 1 pacchetto di 9e 1 pacchetto di 4,

20 + 10 + 9 + 4 = 43 (597)

dove 597ogni termine viene quadrato e sommato insieme (suggerimento: la soluzione ottimale ha questo come valore più alto) . Esistono ovviamente altri modi di fare 43, ma come sai, più pepite per pacco, più economico diventa per pepita. Quindi, si desidera acquistare idealmente il minor numero di confezioni e nelle quantità maggiori per ridurre al minimo i costi.

L'obiettivo

È necessario creare un programma o una funzione che accetta un elenco di numeri interi corrispondenti ai requisiti di ciascuna persona. Dovresti quindi calcolare e stampare l' ordine α più conveniente per acquistare le crocchette di pollo. L' ordine α più conveniente è la combinazione con la quale la somma dei quadrati di ogni quantità è la più alta. Se non v'è assolutamente alcun modo per acquistare perfettamente le pepite, è necessario stampare un valore falsy come 0, False, Impossible!, o tutto ciò che è disponibile nella tua lingua.

Esempio I / O:

[2 7 12 4 15 3] => [20 10 9 4]
     1, 1, 2, 1 => False
  6 5 5 5 5 5 9 => 40
      [6, 4, 9] => 9 10
              1 => 0
            199 => 40, 40, 40, 40, 20, 10, 9
              2 => Impossible!

Ecco l'elenco delle soluzioni ideali per i primi 400. Nota che questi non sono formattati come mi aspetto che il tuo sia, ognuno tupleè nel modulo (N lots of M).

Regole

  1. Nessuna scappatoia standard.
  2. Nessun uso di funzioni integrate che svolgono tutto o la maggior parte dell'attività, come FrobeniusSolvein Mathematica.

α - Per chiarire questo con un esempio, potresti anche fare 43 facendo 4 + 6 + 6 + 9 + 9 + 9 = 43 (319), ma questo non sarebbe ottimale, e quindi un output errato, poiché la somma dei quadrati è inferiore alla combinazione che ho notato nell'introduzione. In sostanza, una maggiore somma di quadrati = costo inferiore = massima efficienza.


Ci sono limiti di tempo / memoria?
Dennis,

@Dennis Non ci sono limiti di tempo o di memoria.
Kade,

4
In realtà è giovedì.
mbomb007,

4
@ mbomb007 Osservazione acuta: P Ho modificato l'intro.
Kade,

2
HO BISOGNO di usare il teorema di mcnugget di pollo in qualche modo ...
Stretch Maniac,

Risposte:


7

Pyth, 26 25 byte

e+Zo.aNf!-TCM"  
("./sQ

Si noti che ci sono alcuni caratteri non stampabili. Provalo online: dimostrazione . È piuttosto lento (ma non lento come la mia soluzione a 26 byte).

Spiegazione:

                          implicit: Q = input list
                     sQ   sum(Q)
                   ./     generate all integer partitions
       f                  filter for partitions T, which satisfy:
             "   ("          string containing chars with the ASCII-values of 4,6,9,10,20,40
           CM                convert each char to the ASCII-value
         -T                  remove this numbers from T
        !                    and check, if the resulting list is empty
    o                      order the remaining subsets N by:
     .aN                      the vector length of N (sqrt of sum of squares)
  +Z                       insert 0 at the beginning
 e                         print the last element

Pyth, 32 byte

e+Zo.aNfqsTsQysm*]d/sQdCM"  
(

Si noti che ci sono alcuni caratteri non stampabili. Provalo online: dimostrazione Questa versione è molto più veloce. Trova la soluzione per l'input [6,7,8]in circa un secondo e la soluzione per l'input [30]in circa 90 secondi.

Spiegazione:

                                 implicit: Q = input list
                          "...(  the string containing chars with the ASCII-values of 4,6,9,10,20,40
                        CM       convert each char to the ASCII-value
                m                map each number d to:
                  ]d                create the list [d]
                 *  /sQd            and repeat it sum(Q)/d times
               s                 unfold
              y                  generate all subsets
        f                        filter for subsets T, which satisfy:
         qsTsQ                      sum(Q) == sum(T)
    o                            order the remaining subsets N by:
     .aN                            the vector length of N (sqrt of sum of squares)
  +Z                             insert 0 at the beginning
 e                               print the last element

Perché è per il sqrt della somma dei quadrati, piuttosto che solo la somma?
mbomb007,

1
@ mbomb007 Perché non importa. Se a> b, allora sqrt (a)> sqrt (b) e viceversa. E l'uso del .ametodo è più breve della quadratura e della somma s^R2.
Jakube,

5

Perl, 175 153

sub f{my$n=$_[0];if(!$n){return 1;}foreach$o(40,20,9,10,6,4){if($n>=$o&&f($n-$o)){print"$o ";return 1;}}return 0;}$n+=$_ for@ARGV;if(!f($n)){print":(";}

Prende l'input dagli argomenti del programma. Stampa a :( se non riesce a trovare una soluzione perfetta.

Codice Ungolfed:

sub f
{
    my $n = $_[0];
    if(!$n)
    {
        return 1;
    }
    foreach $o(40,20,9,10,6,4)
    {
        if($n>=$o&&f($n-$o))
        {
            print "$o ";
            return 1;
        }
    }
    return 0;
}

$n += $_ for @ARGV;
if(!f($n))
{
    print ":(";
}

PS: questa è probabilmente la prima voce che non impiega 10 minuti per 1 2;)

Controllalo qui.


Complimenti per quello che sembra essere il programma più veloce finora! Potrebbe anche essere più veloce del mio programma di riferimento: P Ho aggiunto un link ideone in fondo al tuo post in modo che le persone possano vedere l'output.
Kade,

Il tuo codice può produrre un output errato. L'input 18dovrebbe essere stampato 9 9, no 4 4 10.
Dennis,

Ci sono anche altre uscite errate. Se non sbaglio, puoi sistemarli tutti scambiando l'ordine di 9e 10.
Dennis,

@Dennis Grazie, risolto!
Thomas Oltmann,

3

CJam, 45 29 28 byte

q~:+_[40K9A6Z)U]m*_::+@#=0-p

Si noti che questo approccio è molto lento e richiede molta memoria.

Provalo online nell'interprete CJam .

Può essere accelerato in modo significativo al costo di 5 byte:

q~:+_40/4+[40K9A6Z)U]m*_::+@#=0-p

La complessità è ancora esponenziale nella somma dell'input, ma questo dovrebbe gestire i casi di test fino a 159 con l'interprete online e fino a 199 con l'interprete Java in un paio di secondi.

Provalo online nell'interprete CJam .

Idea

Un acquisto ottimale (somma massima dei quadrati) è un acquisto valido (numero corretto di pepite) che ha il maggior numero di 40 'possibile, quindi il maggior numero di 20 ' possibile, quindi il maggior numero di 9 'possibile (ad esempio, 9 9è preferibile rispetto a 10 4 4) e così via per 10 ', 6 ' e 4 '.

In questo approccio, generiamo il prodotto cartesiano di N copie dell'array [40 20 9 10 6 4 0] , dove N è il numero desiderato di nugget. N è un limite (cattivo) superiore per il numero di acquisti che dobbiamo fare. Nella versione accelerata del codice, utilizziamo invece N / 40 + 4 .

A causa di come viene ordinato l'array, il prodotto cartesiano inizierà con il vettore [40 ... 40] e terminerà con il vettore [0 ... 0] . Calcoliamo l'indice del primo vettore che ha la somma corretta (che avrà anche la somma ottimale dei quadrati), recuperiamo l'elemento di matrice corrispondente, rimuoviamo gli zero che fungevano da segnaposto e stampiamo il risultato.

Se non viene trovato alcun vettore, l'indice sarà -1 , quindi recuperiamo [0 ... 0] , che stamperà invece un array vuoto.

Codice

q~                            e# Read from STDIN and evaluate the input.
  :+                          e# Push N, the sum of all elements of the resulting array.
     [40K9A6Z)U]              e# Push B := [40 20 9 10 6 4 0].
    _           m*            e# Push B**N, the array of all vectors of dimension N
                              e# and coordinates in B.
                  _::+        e# Copy and replace each vector by its sum.
                      @#      e# Get the first index of N.
                        =     e# Retrieve the corresponding element.
                         0-p  e# Remove 0's and print.

Questa potrebbe essere una delle poche situazioni in cui elaborare la soluzione a mano sarebbe più veloce che lasciare che il codice finisca .. bel lavoro a prescindere :)
Kade,

2

Julia, 126 byte

r->(t=filter(i->all(j->j[4,6,9,10,20,40],i),partitions(sum(r)));show(!isempty(t)&&collect(t)[indmax(map(k->sum(k.^2),t))]))

Ciò crea una funzione senza nome che accetta un array come input e stampa un array o un valore booleano su STDOUT, a seconda che esista una soluzione. Per chiamarlo, dagli un nome, ad es f=n->....

Ungolfed + spiegazione:

function f(r)
    # Nugget pack sizes
    packs = [4, 6, 9, 10, 20, 40]

    # Filter the set of arrays which sum to the required number of nuggets
    # to those for which each element is a nugget pack
    t = filter(i -> all(j -> jpacks, i), partitions(sum(r)))

    # Print the boolean false if t is empty, otherwise print the array of
    # necessary nugget packs for which the sum of squares is maximal
    show(!isempty(t) && collect(t)[indmax(map(k -> sum(k.^2), t))])
end

Esempi:

julia> f([1])
false

julia> f([2,7,12,4,15,3])
[20,10,9,4]

1

Python 3 - 265 caratteri

import itertools as i
n=list(map(int,input().split(',')));m=[]
for f in range(1,9):
 for j in range(6*f):
  for x in i.combinations((4,6,9,10,20,40,)*f,j+1):
   if sum(n)==sum(x):m.append(x)
if m!=[]:v=[sum(l**2for l in q)for q in m];print(m[v.index(max(v))])
else:print(0)

Mostra spaziatura:

import itertools as i
n=list(map(int,input().split(',')));m=[]
for f in range(1,5):
 for j in range(6*f):
\tfor x in i.combinations((4,6,9,10,20,40,)*f,j+1):
\t if sum(n)==sum(x):m.append(x)
\t\tif m!=[]:v=[sum(l**2for l in q)for q in m];print(m[v.index(max(v))])
else:print(0)

Supera tutti i casi di test

Nota: non so se questo passerà tutti i casi perché è così lento ... Ma dovrebbe ...


Niente sembra sbagliato in questo momento, lo proverò e vedrò. Una volta tornato a casa, aggiungerò un programma non identificato di riferimento che ho usato per generare l'elenco che si trova nel Gist. Anche se non stavo cronometrando, credo che ci sia voluto da qualche parte nell'intervallo di 8-12 minuti per tutti i casi.
Kade,

@ Vioz- Brilliant! : D
Decadimento beta

Sembra che potrei sbagliarmi, dopo aver testato 36 riesce a superare circa 40 milioni di combinazioni (40.007.602 per l'esattezza) prima di imbattersi in un MemoryError. Questa potrebbe essere una limitazione della mia macchina di lavoro, poiché ha solo 4 GB di memoria.
Kade,

@ Vioz- Hm ... Beh, non c'è speranza per me continuare i test sul mio telefono ...
Decadimento beta

1
@undergroundmonorail Se lo stai usando solo una volta, allora per <= 4 caratteri è meglio importare direttamente (5 pause pari). Ma se lo usi più di una volta, from blah import*è sempre la cosa migliore. L'unica eccezione a cui posso pensare a quanto sopra è se hai più imports, che è l'unica volta che mi viene in mente dove asè effettivamente utile.
Sp3000,

1

JavaScript, 261 256 261

d="length";function g(a){for(z=y=0;y<a[d];z+=+a[y++]);return z}x=[40,20,10,9,6,4];l=prompt().split(",");o=g(l);p=[];for(i=0;i<x[d];i++)r=g(p),s=r+x[i],(s<o-3||s==o)&&p.push(x[i]),(i==x[d]-1||40<o-r)&&r+x[i]<o-3&&(i=-1,0==i||o-r<p[p[d]-1]&&p.pop());g(p)==o&&p||0

Non sono sicuro che vada bene, sembra che funzioni ma sicuramente mi mancano le cose.

Tuttavia, non sembra essere lento, fino a quando 123456non viene emesso [40 x 3086, 10, 6]quasi immediatamente.

Spiegazione:

Scorrendo le dimensioni della pepita (prima la più grande)

  • Se la somma dello stack più la dimensione del nugget è inferiore all'obiettivo - 3 -> spingilo su uno stack
  • Se sono rimasti più di 40 -> resettare il contatore di loop
  • Se la somma dello stack è superiore all'obiettivo quando è stata raggiunta l'ultima dimensione del nugget -> pop l'ultimo elemento, reimpostare il contatore del loop
  • Se la somma dello stack viene sommata, restituirla, altrimenti restituire 0

Per 199 | 1 lo stack creato è simile al seguente

i | stack
0   [40]
0   [40, 40]
0   [40, 40, 40]
0   [40, 40, 40, 40]
0   [40, 40, 40, 40]
1   [40, 40, 40, 40, 20]
2   [40, 40, 40, 40, 20, 10]
3   [40, 40, 40, 40, 20, 10, 9]
4   [40, 40, 40, 40, 20, 10, 9]
5   [40, 40, 40, 40, 20, 10, 9]
==> [40, 40, 40, 40, 20, 10, 9]

Per 1

i | stack
0   []
1   []
2   []
3   []
4   []
5   []
==> 0

1
Il tuo approccio non sembra verificare se l'obiettivo è raggiungibile. 11stampe [6]e 18stampe [10, 4].
Dennis,

@Dennis Ehi, grazie per averlo sottolineato. È stata una notte tarda ieri. Risolto il problema con 5 caratteri. 18 stampato [10,4]perché mi mancava un paio di parentesi. Il controllo era davvero sbagliato, ho appena verificato se ci fosse almeno un elemento nel set di risultati, non se si riassumesse correttamente. Non so cosa pensassi lì
C5H8NNaO4,
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.