Determina se un gettone è canonico


48

L' algoritmo del cassiere è un algoritmo per apportare modifiche al numero minimo di monete che funziona abbastanza bene per la maggior parte dei sistemi valutari. Tuttavia, come la maggior parte degli algoritmi avidi, non è privo di difetti. Se un sistema valutario è impostato nel modo giusto (o semplicemente sbagliato) ci sono alcuni valori in cui l'algoritmo del cassiere non riuscirà a trovare il cambiamento ottimale.

Prendi il seguente esempio:

Abbiamo monete da 4 ¢, 3 ¢ e 1 ¢. Vogliamo fare 6 ¢.

L'algoritmo del cassiere selezionerà prima il maggior numero di monete più grandi (una 4 ¢ per iniziare) e sottrarrà e ripeterà. Ciò comporterà una moneta da 4 ¢ e due monete da 1 ¢, per un totale di 3 monete.

Sfortunatamente per l'algoritmo c'è un modo per fare 6 ¢ con solo due monete (due monete da 3 ¢).

Un sistema di cambiamento sarà considerato canonico se per tutti i valori interi l'algoritmo del cassiere troverà il numero ottimale di monete.

Compito

Il tuo compito sarà quello di prendere un sistema come contenitore non ordinato o contenitore ordinato ordinato di numeri interi che rappresentano valori di moneta e produrre un valore di verità se l'input di sistema è canonico e falsa in caso contrario.

Il tuo programma dovrebbe funzionare per tutti i sistemi in grado di creare qualsiasi valore. (ovvero tutti i sistemi avranno una moneta da 1 ¢)

Questo è il codice golf vince meno byte.

Casi test

Questo elenco non è esaustivo, il tuo programma dovrebbe funzionare per tutti gli input validi

1, 3, 4       -> 0
1, 5, 10, 25  -> 1
1, 6, 10, 25  -> 0
1, 2, 3       -> 1
1, 8, 17, 30  -> 0
1, 3, 8, 12   -> 0
1, 2, 8, 13   -> 0
1, 2, 4, 6, 8 -> 1

@Geobits non significa in ogni caso di più che la differenza cresce o è uguale dalla moneta più piccola alla più grande
Jörg Hülsermann

@ JörgHülsermann Non è neanche abbastanza buono. [1, 6, 13] ha una differenza crescente, ma fallisce ancora su qualcosa come 18 (13 + 1 * 5 invece di 6 * 3).
Geobits,

16
Questi sono chiamati Canonical Coin Systems . Questo breve articolo fornisce un algoritmo a tempo polinomiale per verificare se un sistema di monete è canonico (sebbene un metodo meno efficiente potrebbe essere più golfistico). Un interessante test case sta guadagnando 37 centesimi da 25, 9, 4, 1(da questo post di matematica.SE ) - anche se ogni moneta è più grande della somma di quelle più piccole, il non avido 25, 4, 4, 4batte l'avido 25, 9, 1, 1, 1.
xnor

1
@xnor Nota che 9, 4, 1-> 4, 4, 4essere migliore di quanto 9, 1, 1, 1sia un esempio più rigoroso .
isaacg,

Risposte:


9

Haskell, 94 87 82 byte

f s=and[j i-2<j(i-x)|let j i=last$0:[1+j(i-x)|x<-s,x<i],i<-[1..2*last s],x<-s,x<i]

questa soluzione funziona definendo una funzione jche esegue l'algoritmo del cassiere e ci dice quante monete ha usato il cassiere. controlliamo quindi fino al doppio del numero più grande dell'elenco, supponendo che il sistema sia stato canonico per tutti i numeri precedenti, che prendere la moneta più grande possibile sia la scelta giusta.

questa soluzione presuppone che l'input sia ordinato.

è sufficiente verificare fino a due volte il numero più grande: supponiamo che il sistema non sia canonico per un certo numero ie che ksia il numero più grande nell'elenco non più grande di i. supponiamo che i >= 2kil sistema sia canonico per tutti i numeri inferiori a i.

prendi un modo ottimale per ricavare idelle monete e presumi che non contenga la moneta k. se buttiamo via una delle monete, la nuova somma di monete deve essere maggiore ko minore di i- ma l'algoritmo del cassiere su questo numero userebbe la kmoneta - e quindi, questo insieme di monete può essere sostituito con un uguale insieme di monete contenente la moneta k, e quindi c'è un insieme di monete che contengono la moneta kper il numero i, e per induzione l'algoritmo del cassiere restituisce la scelta ottimale.

questo argomento dimostra davvero che dobbiamo solo controllare fino alla somma dei due elementi più grandi, ma è più lungo farlo.

Modifica: cinque byte di sconto grazie a Ørjan Johansen!


1
È possibile salvare un byte utilizzando letinvece di where. Puoi metterlo come |let ...protezione del modello dopo f so all'interno della comprensione dell'elenco.
Ørjan Johansen,

1
Altri quattro byte con j i=last$0:[1+j(i-k)|k<-s,k<i].
Ørjan Johansen,

5

Pyth, 18 15 byte

!x#eST.gsky_S*e

Suite di test

Un diverso tipo di forza bruta. Questo inizia formando tutte le raccolte di monete con un massimo di k di ciascuna, dove k è la moneta più grande, che si presume sia l'ultima moneta. Credo che ciò sia sempre sufficiente per formare due serie di monete con la stessa somma, una golosa e una più corta, ogni volta che esiste una coppia simile.

Individuo quindi una coppia simile come segue:

I sottoinsiemi sono generati in ordine crescente, e lessicograficamente per posizione nell'input secondario. Raggruppa le collezioni di monete in base alle loro somme, stabilmente. Ogni collezione di monete viene generata in ordine decrescente, quindi la soluzione golosa sarà il primo elemento del gruppo se e solo se la soluzione golosa è ottimale, e sarà l'ultimo elemento del gruppo lessicograficamente. Quindi, troviamo la soluzione golosa e filtriamo su un indice diverso da zero nel gruppo. Se il set di monete è cannonico, questo filtrerà tutto, quindi semplicemente negheremo logicamente il risultato e l'output.

Spiegazione:

!x#eST.gsky_S*e
!x#eST.gsky_S*eQQ   Variable introduction.
                    Q = eval(input()) - sorted list of coins.
              eQ    Greatest coin in the list
             *  Q   Repeat that many times.
            S       Sort the coins
           _        Reverse, so we have the coins in descending order.
          y         Form all subsets, in increasing size then
                    decreasing lexicographic order.
      .gsk          Group by sum
 x#                 Filter by the index in the group of
   eST              The last element lexicographically (greedy solution).
!                   Logically negate.

Molto bello - hai idea del perché si blocca su herokuapp per [1, 2, 4, 6, 8] e viene ucciso con /opt/tryitonline/bin/pyth: line 5: 28070 Killed ... Exit code: 137TIO? Appena esaurito la memoria?
Jonathan Allan,

Questo utilizza 2 ^ (num coin * ultima moneta) byte di memoria. Quindi, per il tuo esempio, 2 ^ 40. Non ci sono molte macchine con un terabyte di RAM
isaacg

Ho pensato che potrebbe essere il caso, la descrizione dell'algoritmo ha un senso, ma non avevo calcolato i numeri - così vasti così in fretta!
Jonathan Allan,

5

PHP, 323 byte

Come altri contano le monete fino alla somma degli ultimi due elementi dell'array

<?function t($g){rsort($g);$m=array_slice($g,1);for($y=1,$i=$g[0];$i<$g[0]+$m[0];$i++){$a=$b=$i;$p=0;$r=$s=[];while($a||$b){$o=$n=0;$g[$p]<=$a?$a-=$r[]=$g[$p]:$o=1;($m[$p]??1)<=$b?$b-=$s[]=$m[$p]:$n=1;$p+=$o*$n;}$y*=count($r)<=count($s);}return$y;}for($i=0,$t=1;++$i<count($a=$_GET[a]);)$t*=t(array_slice($a,0,$i+1));echo$t;

La mia risposta migliore e più lunga credo> 370 byte

Fornisco solo una versione espansa perché è più lunga della mia risposta prima

for($x=1,$n=0,$f=[];++$n<count($a)-1;){
$z=array_slice($a,0,$n+1);
$q=$a[$n]-$a[$n-1];
$i=array_fill(1,$c=max($a[$n+1]??1,11),"X");#$q*$a[$n]
$f=range($a[$n],$c,$q);

$f[]=2*$a[$n];
for($d=[$z[$n]],$j=0;$j<$n;){
   $f[]=$a[$n]+$d[]=$z[$n]-$z[$j++]; 
}

while($f){
    $i[$t=array_pop($f)]="T";
    foreach($d as $g)
    if(($l=$t+$g)<=$c)$f[]=$l;
}

foreach($i as$k=>$v){
    if(in_array($k,$z))$i[$k]="S";
}
#var_dump($i);
if($i[$a[$n+1]]=="X")$x*=0;
}
echo$x;

Spiegazione per questa risposta

Versione online

  1. Impostare tutto nell'array su false == X

  2. Impostare tutti i numeri nell'array che si controlla su S

  3. Trovate differenze tra l'ultima S e l'altra S o 0

  4. Inizia alla fine S nell'array

  5. Impostare tutto il numero su D dove ultimo S + una di tutte le differenze

  6. Inizia a tutti D

  7. IMPOSTARE i valori da "T" a D nell'array

  8. GOTO 5 Ripetilo con tutti i DI trovati non lo ha fatto davvero nel codice

  9. Se l'elemento successivo nell'array ha X, si tratta di un caso falso altrimenti True

Passaggi aggiuntivi La differenza è nel caso dello snippet 3 Tra 1 e 4 sono 2 X Ciò significa che è necessario il secondo D al passaggio 5. Dopo questo valore in questo caso 10 sono tutti i casi veri che ho potuto vedere così lontano che esiste una relazione tra differenza e conteggio nell'array che controlli per calcolare la quantità di D (passaggio 5) necessaria per ottenere il punto prima di trovare l'ultimo caso falso.

È possibile impostare più valori dall'ultimo elemento direttamente su true. Questi punti possono fare la differenza per decidere se il conteggio avido di monete con il valore successivo sia lo stesso del multiplo dell'ultimo dell'array. D'altra parte puoi impostare il nemico

  1. Metti il ​​primo nemico a 1 + Ultima S

  2. Da questo punto aggiungi ogni valore nell'array per impostare i nemici successivi

  3. Inizia con l'ultimo nemico Vai a 2

Se ora hai nemici e casi reali, aumenta la probabilità che i conteggi possano essere gli stessi Con più D la probabilità affonda.

table{width:80%}
td,th{width:45%;border:1px solid blue;}
<table>
  <caption>Working [1,4]</caption>
<tr><th>Number</th><th>Status</th></tr>
<tr><td>1</td><td>S</td></tr>
<tr><td>2</td><td>X</td></tr>
<tr><td>3</td><td>X</td></tr>
<tr><td>4</td><td>S</td></tr>
<tr><td>5</td><td>X</td></tr>
<tr><td>6</td><td>X</td></tr>
<tr><td>7</td><td>D3</td></tr>
<tr><td>8</td><td>D4</td></tr>
<tr><td>9</td><td>X</td></tr>
<tr><td>10</td><td>D3D3</td></tr>
<tr><td>11</td><td>D4D3</td></tr>
<tr><td>12</td><td>D4D4</td></tr>
<tr><td>13</td><td>D3D3D3</td></tr>
<tr><td>14</td><td>D4D3D3</td></tr>
<tr><td>15</td><td>D4D4D4</td></tr>
<tr><td>16</td><td>D4D4D3</td></tr>
</table>
<ul>
  <li>S Number in Array</li>
  <li>D Start|End point TRUE sum Differences from last S</li>
  <li>X False</li>
  </ul>

più? Byte Grazie @JonathanAllan per darmi casi di test errati
262 Bytes Quasi ma non abbastanza bene 4 testcase errati nel momento

i casi test [1,16.256] prima dovrebbero essere veri dopo falsi

<?for($q=[1],$i=0,$t=1,$w=[0,1];++$i<count($a=$_GET[v]);$w[]=$a[$i],$q[]=$m)($x=$a[$i]-$a[$i-1])>=($y=$a[$i-1]-$a[$i-2])&&((($x)%2)==(($m=(($a[$i]+$x)*$a[$i-1])%$a[$i])%2)&&$m>array_sum($q)||(($x)%2)==0&&(($a[$i]-$a[$i-2])*2%$y)==0||in_array($m,$w))?:$t=0;echo$t;

Ordine ascendente dell'array

Spiegazione

for($q=[1],$i=0,$t=1,$w=[0,1] # $t true case $q array for modulos $w checke values in the array
;++$i<count($a=$_GET[v])   #before loop
;$w[]=$a[$i],$q[]=$m) # after loop $q get the modulo from the result and fill $w with the checked value

($x=$a[$i]-$a[$i-1])>=($y=$a[$i-1]-$a[$i-2]) 
# First condition difference between $a[i] and $a[$i-1] is greater or equal $a[$i-1] and $a[$i-2]
# if $a[$-1] == 1 $a[$i-2] will be interpreted as 0
&&  ## AND Operator with the second condition
(
(($x)%2)==   # See if the difference is even or odd
(($m=(($a[$i]+$x)*$a[$i-1])%$a[$i])%2)&&$m>array_sum($q)
# After that we multiply the result with the lower value *$a[$i-1]
    # for this result we calculate the modulo of the result with the greater value %$a[$i]
    # if the difference and the modulo are both even or odd this belongs to true
# and the modulo of the result must be greater as the sum of these before
    # Ask me not why I have make try and error in an excel sheet till I see this relation
||
(($x)%2)==0&&(($a[$i]-$a[$i-2])*2%$y)==0 # or differce modulator is even and difference $a[$i],$a[$i-1] is a multiple of half difference $a[$i-1],$a[$i-2] 
||
in_array($m,$w) # if the modulo result is equal to the values that we have check till this moment in the array we can also neglect the comparison
)
?:$t=0; # other cases belongs to false
echo$t; #Output

Sembra che ciò che ho visto nella tabella contenga valori da [1,2,3,4,5,6] e cambio solo l'ultimo elemento fino a 9. per 2to3 e 4to5 creiamo il valore del valore più basso nella calcolo del modulo

table{width:95%;}th,td{border:1px solid}
<table><tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>35</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>2</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>0</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>7</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>45</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>3</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>3</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>8</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>55</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>7</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>1</td></tr>
<tr><th></th><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>difference</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>4</td></tr>
<tr><th>difference modulo 2</th><td></td><td>1</td><td>1</td><td>1</td><td>1</td><td>0</td></tr>
<tr><th>value</th><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>9</td></tr>
<tr><th>result</th><td></td><td>3</td><td>8</td><td>15</td><td>24</td><td>65</td></tr>
<tr><th>modulo value great</th><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>2</td></tr>
<tr><th>modulo 2</th><td></td><td>1</td><td>0</td><td>1</td><td>0</td><td>0</td></tr></table>


Perché ti dividi ", "quando puoi dividere ","; perché dividi quando potresti prendere un elenco; perché ordini quando potresti prendere un elenco ordinato? (Non sono ancora sicuro se il metodo che stai usando sia infallibile, hai una prova, perché la letteratura che ho sfogliato sembra suggerire che è più difficile di quello che penso stia facendo il tuo codice.)
Jonathan Allan,

@ JörgHülsermann Scusate se ho creato confusione, anche se era diverso prima che ora possiate prendere un elenco ordinato, se lo desiderate.
Wheat Wizard

Temo che dovresti testare più delle mod solo sulle differenze, come un esempio [1,2,5,11,17]è canonico. Forse dai un'occhiata al documento collegato nella mia risposta.
Jonathan Allan,

... e solo per confermarlo con il codice dell'hackeller orgoglioso piuttosto che il mio: ideone.com/C022x0
Jonathan Allan

@WheatWizard è [1,2,5,11,17] vero o falso?
Jörg Hülsermann,

4

JavaScript (ES6), 116 125 130

l=>eval("r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;for(x=l[0]*2;--x>1;r(x,g))g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));x")

Ciò richiede che l'array di input sia ordinato in ordine decrescente. Per ogni valore compreso tra 2N e 2 (N è il valore massimo della moneta), trova il numero di monete dall'algoritmo goloso e cerca di trovare un insieme più piccolo di monete.

Meno golf

l=>{
  // recursive function to to find a smaller set of coins
  // parameter k is the max coin limit
  r = (d,k) => d // check if difference is not 0
     ? --k // if not, and if the number of coins used will be less than limit
      && l.map(v => v>d || r(d-v, k))  // proceed with the recursive search
     : x=1 // if diff is 0, value found, set x to 1 to stop the loop
  for( x=l[0]*2; --x > 1; )  
    g=0, h=x, l.map(v=>(g += h/v|0, h %= v)), // find g with the greedy algorithm
    r(x,g) // call with initial difference equal to target value
  return x
}

Test

f=
l=>eval("r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;for(x=l[0]*2;--x>1;r(x,g))g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));x")

/* No eval
f=l=>{
  r=(d,k)=>d?--k&&l.map(v=>v>d||r(d-v,k)):x=1;
  for(x=l[0]*2;--x>1;r(x,g))
    g=0,h=x,l.map(v=>(g+=h/v|0,h%=v));
  return x;
}*/

;[
 [[100,50,20,10,5,2,1],1], [[4,3,1],0],
 [[25,10,5,1],1], [[25,10,6,1],0],
 [[3,2,1],1], [[30,17,8,1], 0], 
 [[12,8,3,1],0], [[13,8,2,1], 0]
].forEach(t=>{
  var i=t[0],k=t[1],r=f(i),
      msg=((r==k)?'OK ':'KO ')+i+' -> '+r
      + (r==k?'':' (should be '+k+')')
  O.textContent += msg+'\n'
})

function test()
{
  var i=I.value.match(/\d+/g).map(x=>+x).sort((a,b)=>b-a)
  O.textContent = i+' -> '+f(i)+'\n'+O.textContent
 }
#I { width:50% }
<input id=I value='1 4 9'><button onclick='test()'>test</button>
<pre id=O></pre>


4

Python, 218 211 205 byte

-1 byte grazie a @TuukkaX (uno spazio potrebbe essere eliminato tra <3e or)

from itertools import*
g=lambda x,c,n=0:x and g(x-[v for v in c if v<=x][0],c,n+1)or n
lambda c:len(c)<3or 1-any(any(any(x==sum(p)for p in combinations(c*i,i))for i in range(g(x,c)))for x in range(c[0]*2))

repl.it

Immettere in ordine decrescente.

Forza orribilmente bruta. Qualsiasi set di una moneta unitaria e qualche altra moneta è canonico. Per i set più grandi il più piccolo caso di fallimento, se ne esiste uno sarà maggiore o uguale alla terza moneta più piccola (non sono sicuro di come potrebbe essere uguale!) E inferiore alla somma delle due monete più grandi - vedi questo documento (che in realtà fa riferimento ad un altro ma fornisce anche un metodo O (n ^ 3)).

g conta le monete usate dal metodo avido e la funzione senza nome attraversa i possibili candidati (in realtà da 0 a una in meno del doppio della moneta più grande per salvare byte) e cerca qualsiasi raccolta di meno monete che si sommino anche a tale importo.

gfunziona eseguendo ciò che un cassiere sarebbe, ci vuole in modo ricorsivo la più grande moneta minore o uguale all'importo ancora da make up, [v for v in c if v<=x][0]via, e conta in avanti il numero di monete utilizzate, n.

La funzione senza nome restituisce 1 se len(c)è inferiore a 3, e in caso contrario verifica che non sia così, 1-...che qualsiasi valore nella gamma di possibilità range(c[0]*2))), è possibile con meno monete, i in range(g(x,c))facendo una raccolta di quel numero di tutte le monete, c*ied esaminando tutte le combinazioni di imonete, combinations(c*i,i)per verificare l'eventuale somma dello stesso valore.


@WheatWizard restituisce False per [13,8,2,1] - L'ho aggiunto ai casi di test. Aggiunto chiarimento che l'input è in ordine decrescente.
Jonathan Allan,

1
3ordovrebbe funzionare.
Yytsi,

Grazie @TuukkaX, anche io potrei sostituirlo not(...)con1-...
Jonathan Allan il

2

Jelly ( fork ), 15 14 byte

SRæFµS€Ṃ=$Ṫµ€Ȧ

Questa soluzione utilizza i limiti per i contro-esempi di questo documento . Lì, l'autore usa un limite stretto per il contro-esempio, ma nell'interesse del golf, viene utilizzato l'intervallo della somma delle denominazioni delle monete che è più grande e contiene quel limite.

Questo programma calcola tutti i casi di test in meno di un secondo sulla mia macchina.

Sfortunatamente, questo si basa su un ramo di Jelly in cui stavo lavorando per implementare un atom di risoluzione di Frobenius, quindi non puoi provarlo online.

uso

$ ./jelly eun 'SRæFµS€Ṃ=$Ṫµ€Ȧ' '1,2,4,6,8'
1

Le prestazioni sono buone e possono risolvere tutti i casi di test contemporaneamente in meno di un secondo.

$ time ./jelly eun 'SRæFµS€Ṃ=$Ṫµ€Ȧ¶Ç€' '[[1,3,4],[1,5,10,25],[1,6,10,25],[1,2,3],[1,8,17,30],[1,3,8,12],[1,2,8,13],[1,2,4,6,8]]'
[0, 1, 0, 1, 0, 0, 0, 1]

real    0m0.793s
user    0m0.748s
sys     0m0.045s

Spiegazione

SRæFµS€Ṃ=$Ṫµ€Ȧ  Input: list of integers C
    µ           Start a new monadic chain
S                 Sum
 R                Range, [1, 2, ..., sum(C)]
  æF              Frobenius solve for each X in the range using coefficients from C
                  This generates all vectors where the dot product of a
                  vector with C equals X, ordered by using values from the
                  start to end of C
           µ€   Start a new monadic chain that operates on each list of vectors
     S€           Sum each vector
         $        Monadic hook on the sums
       Ṃ            Minimum (This is the optimal solution)
        =           Vectorized equals, 1 if true else 0
          Ṫ       Tail (This is at the index of the greedy solution)
             Ȧ  All, returns 0 if it contains a falsey value, else 1

2

JavaScript (ES6), 144 132 124 122 110 byte

a=>![...Array(a[0]*2)].some((_,i)=>(g=(a,l=0,n=i)=>[a.filter(c=>c>n||(l+=n/c|0,n%=c,0)),-l*!n])(...g(a))[1]>0)

Richiede che l'array sia ordinato in ordine decrescente. Usa l'osservazione nel documento collegato che se il sistema non è canonico, allora c'è almeno un valore inferiore a 2a [0] che prende meno monete quando viene decomposto usando le monete non utilizzate dall'algoritmo goloso iniziale.

Modifica: ho salvato 12 byte rendendomi conto che avrei potuto controllare tutte le monete anche se avevo già raggiunto il valore target. Ho salvato 8 byte cambiando il mio output intermedio da [l,b]a [b,-l]; questo mi ha permesso di passare direttamente il primo risultato come parametro della seconda chiamata, oltre a un piccolo salvataggio per rilevare se la seconda chiamata ha avuto successo. Ho salvato 2 byte spostando la definizione gnel somecallback, permettendomi di evitare di passare inutilmente due volte nella variabile loop. Ho salvato 12 byte passando dalla mia funzione di supporto ricorsivo a una chiamata filter(resa possibile dal mio interruttore di uscita intermedio).


2

Perl, 69 byte

Include +2 per -pa

Dare le monete in ordine decrescente su STDIN. Opzionalmente puoi lasciare fuori la 1moneta.

coins.pl <<< "4 3 1"

coins.pl:

#!/usr/bin/perl -pa
$_=!map{grep$`>=$_&&($n=$G[$`-$_]+1)<($G[$`]||=$n),@F,/$/}1..2*"@F"

Aumenta il numero di monete utilizzate dall'algoritmo di cassa @Gper importi da 1 a due volte la moneta più grande. Per ogni importo viene verificato che se tale importo viene ridotto di 1 valore in monete l'algoritmo della cassa necessita al massimo di 1 moneta in meno. Altrimenti questo è un controesempio (o c'era un controesempio precedente). Potrei fermarmi al primo controesempio, ma questo richiede più byte. Quindi la complessità del tempo è O(max_coin * coins)e la complessità dello spazio èO(max_coin)

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.