Bir bozuk para sisteminin Kanonik olup olmadığını belirlemek


48

Kasiyer Algoritması en kur sistemleri için oldukça iyi çalışıyor paralar az sayıda değişikliği yapmak için bir algoritmadır. Bununla birlikte, çoğu açgözlü algoritmalarda olduğu gibi, kusurları yoktur. Bir para birimi sistemi doğru (ya da sadece yanlış) kurulursa, Kasiyerin Algoritmasının en uygun değişikliği bulamayacağı belirli değerler vardır.

Aşağıdaki örneği ele alalım:

4 ¢, 3 and ve 1 ¢ madeni paralarımız var. 6 ¢ yapmak istiyoruz.

Kasiyer Algoritması ilk önce en büyük madeni paradan birini (başlangıç ​​için bir 4 ¢) seçecek ve çıkartıp tekrarlayacaktır. Bu, toplam 3 jeton için bir adet 4 jeton ve iki adet 1 jetonla sonuçlanacaktır.

Ne yazık ki Algoritma için sadece iki jetonla (iki 3 ¢ jeton) 6 make yapmanın bir yolu var.

Kasiyer Algoritması en uygun para sayısını bulabilecek tüm tamsayı değerleri için kanonik bir değişim sistemi olarak kabul edilecektir.

Görev

Göreviniz bir sistemi düzensiz bir kap ya da jeton değerlerini temsil eden tamsayıların sıralı bir kapsayıcısı olarak almak ve eğer sistem girdisi kanonikse ve yanlışsa, bir truthy değeri çıkarmak olacaktır.

Programınız, herhangi bir değer yaratabilecek tüm sistemler için çalışmalıdır. (yani tüm sistemlerde 1 ¢ jeton olacaktır)

Bu kod golf en az bayt kazanır.

Test durumları

Bu liste eksiksiz değildir, programınız tüm geçerli girdiler için çalışmalıdır.

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

@Geobitler her durumda değil, en küçük paradan en büyüğe doğru büyüyen ya da eşit olan farkın daha fazla olduğu anlamına gelir
Jörg Hülsermann 13:16

@ JörgHülsermann Bu da yeterince iyi değil. [1, 6, 13], artan bir fark yaratıyor, ancak 18 gibi bir şeyde başarısız oluyor (6 * 3 yerine 13 + 1 * 5).
Geobits

16
Bunlara Kanonik Para Sistemleri denir . Bu kısa yazı , bir madeni para sisteminin kanonik olup olmadığını kontrol etmek için polinom-zaman algoritması verir (daha az verimli bir yöntem golfçüler olsa da). İlginç bir test vakası 25, 9, 4, 1( bu matematikten yazılandan 37 sent ) yapmaktır - her madalyonun küçük paraların toplamından daha büyük olmasına rağmen, açgözlü olmayanlar açgözlülüğü 25, 4, 4, 4atmaktadır 25, 9, 1, 1, 1.
xnor

1
@xnor 9, 4, 1- - 4, 4, 4Daha 9, 1, 1, 1sıkı olmanın daha iyi bir örnek olduğuna dikkat edin .
isaacg

Yanıtlar:


9

Haskell, 94 87 82 bayt

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]

bu çözüm jkasiyerin algoritmasını yapan bir fonksiyon tanımlayarak çalışır ve kasiyerin kaç para kullandığını gösterir. Daha sonra, sistemin önceki tüm sayılar için kanonik olduğunu ve mümkün olan en büyük madeni parayı almanın doğru seçim olduğunu varsayarak listedeki en büyük sayının iki katına kadar kontrol ediyoruz.

bu çözüm girişin sıralandığını varsayar.

ispat kontrolü en büyük sayının iki katına çıkması yeterlidir: sistemin bir sayı için kanonik olmadığını varsayalım ve listedeki en büyük sayı iolalım . varsayalım ve sistem tüm sayılardan daha az kanoniktir .kii >= 2ki

imadeni paralardan kurtulmak için en uygun yöntemi kullanın ve madeni para içermediğini varsayalım k. Eğer bir jetondan birini atarsak, yeni jeton toplamı ondan daha büyük kve daha küçük olmalıdır i- fakat kasiyerin bu sayıdaki algoritması kjetonu kullanır - ve dolayısıyla, bu jeton takımı eşit bir jeton grubuyla değiştirilebilir yazı tura içeren kve bu nedenle k, numara için yazı tura içeren bir yazı tura sahiptir ive indüksiyonla kasiyerin algoritması en uygun seçimi verir.

Bu argüman gerçekten sadece en büyük iki elementin toplamına kadar kontrol etmemiz gerektiğini gösteriyor - ama bunu yapmak daha uzun.

Düzenleme: Ørjan Johansen sayesinde beş bayt!


1
Sen kullanarak bir bayt kaydedebilirsiniz letyerine where. Onu |let ...sonradan bir desen koruyucusu olarak f sya da liste kavrayışına koyabilirsiniz .
Ørjan Johansen

1
İle başka bir dört bayt j i=last$0:[1+j(i-k)|k<-s,k<i].
Ørjan Johansen

5

Pyth, 18 15 bayt

!x#eST.gsky_S*e

Test odası

Farklı bir kaba kuvvet türü. Bu, k'nin en son sikke olduğu kabul edilen en büyük sikke olduğu, her birinin k'ye kadar olan bütün para koleksiyonlarını oluşturarak başlar. Bunun her zaman böyle bir çift olduğu zaman, aynı açgözlü, biri açgözlü ve kısa olan iki madeni para seti oluşturmak için yeterli olduğuna inanıyorum.

Sonra böyle bir çift buluyorum:

Alt kümeler, artan boyut sırasına göre ve sözlükte ikinci sırada girdilerde konumlarına göre üretilir. Madeni para koleksiyonlarını toplamlarına göre sabit bir şekilde gruplandırın. Her bir madeni para toplama işlemi azalan sırayla üretilir, bu nedenle açgözlü çözüm, eğer yalnızca açgözlü çözüm en uygunsa grubun ilk elemanı olacaktır ve sözlü olarak grubun son elemanı olacaktır. Böylece, açgözlü çözümü bulmak ve grup içinde sıfır olmayan bir dizin üzerinde filtre. Bozuk para seti topal ise, bu her şeyi filtreleyecektir, bu nedenle sonucu ve çıktısını mantıksal olarak olumsuzlarız.

Açıklama:

!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.

Çok hoş - neden [1, 2, 4, 6, 8] için herokuapp'a takıldığı ve TIO'da öldürüldüğü hakkında bir fikriniz var /opt/tryitonline/bin/pyth: line 5: 28070 Killed ... Exit code: 137mı? Sadece bellek yetersiz mi?
Jonathan Allan,

Bu, 2 ^ (num sikke * son jeton) bayt belleği kullanır. Yani, örneğin, 2 ^ 40. Terabayt RAM'e sahip çok fazla makine yok
isaacg

Durumun bu olabileceğini düşündüm, algoritmanın tanımı mantıklı geliyor, ama sayıları hesaplamamıştım - çok hızlı!
Jonathan Allan,

5

PHP, 323 Bayt

Diğerleri ile aynı şekilde dizideki son iki elementin toplamına kadar jetonları say.

<?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;

En iyi ve en uzun cevabım inanıyorum> 370 Bayt

Sadece genişletilmiş bir sürüm verdim çünkü daha önce cevabımdan daha uzun

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;

Bu cevap için açıklama

Çevrimiçi sürüm

  1. Dizideki hepsini false olarak ayarla == X

  2. Kontrol ettiğiniz dizideki tüm numaraları S olarak ayarlayın.

  3. Son S ve diğer S veya 0 arasında fark bulundu

  4. Dizideki son S'den başla

  5. Tüm sayıları D olarak ayarla En Son S + tüm farklılıklardan biri

  6. D ile başla

  7. Dizi "T" D değerleri D

  8. GOTO 5 Bulunan tüm DI ile tekrarlayın, gerçekten kodda değildi

  9. Dizi içindeki bir sonraki öğenin X değeri varsa, bu yanlış bir durumdur.

Ek Adımlar Snippet 3'teki fark söz konusudur. 1 ile 4 arasında 2 X vardır. Bu, 5. Adımda ikinci D'ye ihtiyaç duyduğunuz anlamına gelir. En son yanlış vakayı bulmadan önce puan almak için ne kadar D (Adım 5) almanız gerektiğini hesaplamak için dizideki fark ve sayım arasında.

Son öğeden doğrudan doğru seçeneğine birden çok değer ayarladınız. Bu Noktalar, bir sonraki değere sahip açgözlü jeton sayısının, dizideki son sayının çoğunun aynı olup olmadığına karar vermek için bir fark yaratabilir. Diğer taraftan, düşmanı ayarlayabilirsin

  1. İlk düşmanı 1 + Son S olarak ayarlayın

  2. Bu noktadan sonraki düşmanları ayarlamak için diziye her bir değer ekleyin

  3. Son düşman Goto 2 ile başla

Eğer şimdi düşmanlarınız ve gerçek durumlarınız varsa, sayıları aynı olabilme olasılığı büyür. Daha fazla D ile olasılık batırılır.

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>

artı? Bytes Teşekkürler @JonathanAllan bana yanlış test senaryoları veriyor
262 Bytes Şu anda neredeyse ama yeterince iyi değil 4 yanlış test çantası

Test vakaları [1,16,256] daha önce yanlış sonra doğru olmalı

<?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;

Dizinin Artan Sırası

açıklama

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

Tabloda gördüğüm gibi [1,2,3,4,5,6] 'dan değerler içeriyor gibi gözüküyor ve sadece son öğeyi 9'a kadar değiştiriyorum. 2'den 3'e ve 4'den 5'e kadar modulo hesaplama

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>


Ne ", "zaman ayrılabileceğinizi neden ayırıyorsunuz ","; bir liste alabilirken neden ayrılıyorsun; bir sıralama listesini ne zaman alabileceğinizi neden sıralıyorsunuz? (İçinden yağsız olması literatür zor ne daha önermek gibi görünüyor, çünkü sana bir kanıt var, ayrıca kullandığınız yöntem yanılmaz ise hala emin değilim düşünüyorum kodunuzu yapıyor.)
Jonathan Allan

@ JörgHülsermann Herhangi bir karışıklığa neden olduğum için özür dilerim, daha önce farklı olmasına rağmen, şimdi isterseniz bir sıralama listesini alabilir.
Buğday Sihirbazı

Korkarım ki [1,2,5,11,17], kanonik olduğu için, farklılıklar üzerine sadece mod 2'den daha fazlasını test etmeniz gerekecek . Belki de cevabımla bağlantılı gazeteye bir göz atın.
Jonathan Allan,

... ve sadece benimkinden ziyade gururlu haskeller'in koduyla doğrulamak için: ideone.com/C022x0
Jonathan Allan

@WheatWizard [1,2,5,11,17] doğru mu yanlış mı?
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")

Bunun için giriş sırasının azalan düzende sıralanması gerekir. 2N'den 2'ye kadar olan her değer için (N, en fazla jeton değeridir), açgözlü algoritmadan elde edilen jeton sayısını bulur ve daha küçük bir jeton seti bulmaya çalışır.

Daha az golf oynadı

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
}

Ölçek

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 bayt

@TuukkaX sayesinde -1 bayt ( <3ve arasında bir boşluk silinebilir 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

Azalan sırayla giriş.

Korkunç kaba kuvvet. Herhangi bir tek ünite jeton seti ve diğer bazı madeni paralar kanoniktir. Daha büyük setler için en küçük başarısızlık durumu, eğer biri varsa, en küçük 3. bozuk paraya eşit veya ondan daha büyükse (kendimin nasıl eşit olacağından emin değilim!) Ve en büyük iki madenin parasının toplamından daha azsa - bu makaleyi görün (aslında bir başkasına atıfta bulunur, ancak O (n ^ 3) yöntemini de verir).

g açgözlü yöntem tarafından kullanılan paraları sayar ve adsız işlev, olası adayları (gerçekte 0 ila bir büyüklüğünden daha az olan baytları kurtarmak için) geçer ve bu miktarda toplanan daha az bozuk para koleksiyonuna bakar.

gBir kasiyerin ne yapacağını yerine getirerek çalışır, tekrarlı bir şekilde en büyük parayı, hala telafi etmek için harcadığınız miktara eşit veya daha az alır ve [v for v in c if v<=x][0]kullanılan jeton sayısını sayar n.

Adsız işlev len(c), 3'ten küçükse 1 değerini döndürür ve aksi takdirde 1-..., olasılık aralığındaki herhangi bir değerin , her bozuk paranın çoğunun bir koleksiyonunu yaparak, range(c[0]*2)))daha az i in range(g(x,c))parayla mümkün olduğunu test eder. c*ive aynı değere sahip olup olmadığını görmek için tüm imadeni para kombinasyonlarını incelemek combinations(c*i,i).


@WheatWizard [13,8,2,1] için False döndürür - Test vakalarına ekledim. Girişin azalan düzende olduğuna dair açıklama eklendi.
Jonathan Allan,

1
3orçalışmalı.
Yytsi

Teşekkür ayrıca yerini alabilir, @TuukkaX not(...)ile1-...
Jonathan Allan

2

Jöle ( çatal ), 15 14 bayt

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

Bu çözüm, bu makalenin karşı örnekleri için sınırları kullanır . Burada yazar, karşı örnek için sıkı bir sınır kullanıyor, ancak golf oynamak için, daha büyük ve sınırlandırılmış olan madeni paraların toplamı aralığı kullanılıyor.

Bu program tüm test durumlarını makinemde bir saniyeden daha kısa sürede hesaplıyor.

Ne yazık ki, bu bir Frobenius çözme atomu uygulamak için çalıştığım Jelly dalına dayanıyor, böylece çevrimiçi deneyemezsiniz.

kullanım

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

Performans iyidir ve tüm test durumlarını bir saniyeden daha kısa sürede bir seferde çözebilir.

$ 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

açıklama

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 bayt

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)

Dizinin azalan düzende sıralanmasını gerektirir. Bağlantılı makalede gözlemi kullanır, eğer sistem kanonik değilse, başlangıç ​​açgözlü algoritmasından kullanılmayan paralar kullanılarak ayrıştırıldığında daha az para alan daha az 2a [0] 'dan daha az bir değer vardır.

Düzenleme: Zaten hedef değere ulaşmış olmama rağmen tüm paraları kontrol edebileceğimi fark ederek 12 bayt kaydedildi. Ara çıkışımı 'dan' [l,b]a değiştirerek 8 baytlık tasarruf sağladı [b,-l]; bu, ilk sonucu doğrudan ikinci aramanın parametresi olarak geçirmeme izin verdi, ayrıca ikinci aramanın başarılı olup olmadığını belirleyen küçük bir tasarruf sağladı. Döngü değişkenine gereksiz yere iki kez geçmeme izin vermeme izin vererek g, somegeri çağırma tanımını hareket ettirerek 2 bayt kurtarıldı . Özyinelemeli yardımcı fonksiyonumdan bir çağrıya filter(ara çıkış anahtarım ile mümkün) yapılan bir çağrıya geçerek 12 bayt kaydedildi .


2

Perl, 69 bayt

İçin +2 içerir -pa

STDIN'de azalan sırayla para verin. İsteğe bağlı olarak 1bozuk para bırakabilirsiniz .

coins.pl <<< "4 3 1"

coins.pl:

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

Kasiyer algoritması tarafından kullanılan jeton sayısını, @Gen büyük jetonun 1 ila iki katı kadar tutar. Her bir miktar için, bu tutar 1 jeton değerine düşürülürse, kasiyer algoritmasının en az 1 jetona ihtiyacı olduğunu kontrol eder. Aksi takdirde, bu bir karşı örnek (veya daha önceki bir karşı örnek vardı). İlk karşı örnekte durabilirim ama bu daha fazla bayt alır. Yani zaman karmaşıklığı O(max_coin * coins)ve uzay karmaşıklığıO(max_coin)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.